gitlab.com/SiaPrime/SiaPrime@v1.4.1/modules/host/newrpc.go (about)

     1  package host
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"math/bits"
     7  	"sort"
     8  	"sync/atomic"
     9  	"time"
    10  
    11  	bolt "github.com/coreos/bbolt"
    12  	"gitlab.com/NebulousLabs/fastrand"
    13  	"gitlab.com/SiaPrime/SiaPrime/crypto"
    14  	"gitlab.com/SiaPrime/SiaPrime/modules"
    15  	"gitlab.com/SiaPrime/SiaPrime/types"
    16  )
    17  
    18  // managedRPCLoopSettings writes an RPC response containing the host's
    19  // settings.
    20  func (h *Host) managedRPCLoopSettings(s *rpcSession) error {
    21  	atomic.AddUint64(&h.atomicSettingsCalls, 1)
    22  	s.extendDeadline(modules.NegotiateSettingsTime)
    23  
    24  	h.mu.Lock()
    25  	hes := h.externalSettings()
    26  	h.mu.Unlock()
    27  	js, _ := json.Marshal(hes)
    28  	resp := modules.LoopSettingsResponse{
    29  		Settings: js,
    30  	}
    31  	if err := s.writeResponse(resp); err != nil {
    32  		return err
    33  	}
    34  	return nil
    35  }
    36  
    37  // managedRPCLoopLock handles the LoopLock RPC.
    38  func (h *Host) managedRPCLoopLock(s *rpcSession) error {
    39  	s.extendDeadline(modules.NegotiateRecentRevisionTime)
    40  
    41  	// Read the request.
    42  	var req modules.LoopLockRequest
    43  	if err := s.readRequest(&req, modules.RPCMinLen); err != nil {
    44  		s.writeError(err)
    45  		return err
    46  	}
    47  
    48  	// Another contract may already be locked; locking multiple contracts is
    49  	// not allowed.
    50  	if len(s.so.OriginTransactionSet) != 0 {
    51  		err := errors.New("another contract is already locked")
    52  		s.writeError(err)
    53  		return err
    54  	}
    55  
    56  	// Sanity-check the lock timeout
    57  	lockTimeout := time.Duration(req.Timeout) * time.Millisecond
    58  	if lockTimeout > maxObligationLockTimeout {
    59  		err := errors.New("lock timeout is too long")
    60  		s.writeError(err)
    61  		return err
    62  	}
    63  
    64  	var newSO storageObligation
    65  	h.mu.RLock()
    66  	err := h.db.View(func(tx *bolt.Tx) error {
    67  		var err error
    68  		newSO, err = getStorageObligation(tx, req.ContractID)
    69  		return err
    70  	})
    71  	h.mu.RUnlock()
    72  	if err != nil {
    73  		s.writeError(errors.New("no record of that contract"))
    74  		return extendErr("could get storage obligation "+req.ContractID.String()+": ", err)
    75  	}
    76  
    77  	// get the revision and signatures
    78  	txn := newSO.RevisionTransactionSet[len(newSO.RevisionTransactionSet)-1]
    79  	rev := txn.FileContractRevisions[0]
    80  	var sigs []types.TransactionSignature
    81  	for _, sig := range txn.TransactionSignatures {
    82  		// The transaction may have additional signatures that are only
    83  		// relevant to the host.
    84  		if sig.ParentID == crypto.Hash(rev.ParentID) {
    85  			sigs = append(sigs, sig)
    86  		}
    87  	}
    88  
    89  	// verify the challenge response
    90  	hash := crypto.HashAll(modules.RPCChallengePrefix, s.challenge)
    91  	var renterPK crypto.PublicKey
    92  	var renterSig crypto.Signature
    93  	copy(renterPK[:], rev.UnlockConditions.PublicKeys[0].Key)
    94  	copy(renterSig[:], req.Signature)
    95  	if crypto.VerifyHash(hash, renterPK, renterSig) != nil {
    96  		err := errors.New("challenge signature is invalid")
    97  		s.writeError(err)
    98  		return err
    99  	}
   100  
   101  	// attempt to lock the storage obligation
   102  	lockErr := h.managedTryLockStorageObligation(req.ContractID, lockTimeout)
   103  	if lockErr == nil {
   104  		s.so = newSO
   105  	}
   106  
   107  	// Generate a new challenge.
   108  	fastrand.Read(s.challenge[:])
   109  
   110  	// Write the response.
   111  	resp := modules.LoopLockResponse{
   112  		Acquired:     lockErr == nil,
   113  		NewChallenge: s.challenge,
   114  		Revision:     rev,
   115  		Signatures:   sigs,
   116  	}
   117  	if err := s.writeResponse(resp); err != nil {
   118  		return err
   119  	}
   120  	return nil
   121  }
   122  
   123  // managedRPCLoopUnlock handles the LoopUnlock RPC. No response is sent.
   124  func (h *Host) managedRPCLoopUnlock(s *rpcSession) error {
   125  	s.extendDeadline(modules.NegotiateSettingsTime)
   126  	if len(s.so.OriginTransactionSet) != 0 {
   127  		h.managedUnlockStorageObligation(s.so.id())
   128  		s.so = storageObligation{}
   129  	}
   130  	return nil
   131  }
   132  
   133  // managedRPCLoopWrite reads an upload request and responds with a signature
   134  // for the new revision.
   135  func (h *Host) managedRPCLoopWrite(s *rpcSession) error {
   136  	s.extendDeadline(modules.NegotiateFileContractRevisionTime)
   137  	// Read the request.
   138  	var req modules.LoopWriteRequest
   139  	if err := s.readRequest(&req, modules.SectorSize*5); err != nil {
   140  		// Reading may have failed due to a closed connection; regardless, it
   141  		// doesn't hurt to try and tell the renter about it.
   142  		s.writeError(err)
   143  		return err
   144  	}
   145  	// If no Merkle proof was requested, the renter's signature should be
   146  	// sent immediately.
   147  	var sigResponse modules.LoopWriteResponse
   148  	if !req.MerkleProof {
   149  		if err := s.readResponse(&sigResponse, modules.RPCMinLen); err != nil {
   150  			return err
   151  		}
   152  	}
   153  
   154  	// Check that a contract is locked.
   155  	if len(s.so.OriginTransactionSet) == 0 {
   156  		err := errors.New("no contract locked")
   157  		s.writeError(err)
   158  		return err
   159  	}
   160  
   161  	// Read some internal fields for later.
   162  	h.mu.Lock()
   163  	blockHeight := h.blockHeight
   164  	secretKey := h.secretKey
   165  	settings := h.externalSettings()
   166  	h.mu.Unlock()
   167  	currentRevision := s.so.RevisionTransactionSet[len(s.so.RevisionTransactionSet)-1].FileContractRevisions[0]
   168  
   169  	// Process each action.
   170  	newRoots := append([]crypto.Hash(nil), s.so.SectorRoots...)
   171  	sectorsChanged := make(map[uint64]struct{}) // for construct Merkle proof
   172  	var bandwidthRevenue types.Currency
   173  	var sectorsRemoved []crypto.Hash
   174  	var sectorsGained []crypto.Hash
   175  	var gainedSectorData [][]byte
   176  	for _, action := range req.Actions {
   177  		switch action.Type {
   178  		case modules.WriteActionAppend:
   179  			if uint64(len(action.Data)) != modules.SectorSize {
   180  				s.writeError(errBadSectorSize)
   181  				return errBadSectorSize
   182  			}
   183  			// Update sector roots.
   184  			newRoot := crypto.MerkleRoot(action.Data)
   185  			newRoots = append(newRoots, newRoot)
   186  			sectorsGained = append(sectorsGained, newRoot)
   187  			gainedSectorData = append(gainedSectorData, action.Data)
   188  
   189  			sectorsChanged[uint64(len(newRoots))-1] = struct{}{}
   190  
   191  			// Update finances
   192  			bandwidthRevenue = bandwidthRevenue.Add(settings.UploadBandwidthPrice.Mul64(modules.SectorSize))
   193  
   194  		case modules.WriteActionTrim:
   195  			numSectors := action.A
   196  			if uint64(len(newRoots)) < numSectors {
   197  				err := errors.New("trim size exceeds number of sectors")
   198  				s.writeError(err)
   199  				return err
   200  			}
   201  			// Update sector roots.
   202  			sectorsRemoved = append(sectorsRemoved, newRoots[uint64(len(newRoots))-numSectors:]...)
   203  			newRoots = newRoots[:uint64(len(newRoots))-numSectors]
   204  
   205  			sectorsChanged[uint64(len(newRoots))] = struct{}{}
   206  
   207  		case modules.WriteActionSwap:
   208  			i, j := action.A, action.B
   209  			if i >= uint64(len(newRoots)) || j >= uint64(len(newRoots)) {
   210  				err := errors.New("illegal sector index")
   211  				s.writeError(err)
   212  				return err
   213  			}
   214  			// Update sector roots.
   215  			newRoots[i], newRoots[j] = newRoots[j], newRoots[i]
   216  
   217  			sectorsChanged[i] = struct{}{}
   218  			sectorsChanged[j] = struct{}{}
   219  
   220  		case modules.WriteActionUpdate:
   221  			sectorIndex, offset := action.A, action.B
   222  			if sectorIndex >= uint64(len(newRoots)) {
   223  				err := errors.New("illegal sector index or offset")
   224  				s.writeError(err)
   225  				return err
   226  			} else if offset+uint64(len(action.Data)) > modules.SectorSize {
   227  				s.writeError(errIllegalOffsetAndLength)
   228  				return errIllegalOffsetAndLength
   229  			}
   230  			// Update sector roots.
   231  			sector, err := h.ReadSector(newRoots[sectorIndex])
   232  			if err != nil {
   233  				s.writeError(err)
   234  				return err
   235  			}
   236  			copy(sector[offset:], action.Data)
   237  			newRoot := crypto.MerkleRoot(sector)
   238  			sectorsRemoved = append(sectorsRemoved, newRoots[sectorIndex])
   239  			sectorsGained = append(sectorsGained, newRoot)
   240  			gainedSectorData = append(gainedSectorData, sector)
   241  			newRoots[sectorIndex] = newRoot
   242  
   243  			// Update finances.
   244  			bandwidthRevenue = bandwidthRevenue.Add(settings.UploadBandwidthPrice.Mul64(uint64(len(action.Data))))
   245  
   246  		default:
   247  			err := errors.New("unknown action type " + action.Type.String())
   248  			s.writeError(err)
   249  			return err
   250  		}
   251  	}
   252  
   253  	// Update finances.
   254  	var storageRevenue, newCollateral types.Currency
   255  	if len(newRoots) > len(s.so.SectorRoots) {
   256  		bytesAdded := modules.SectorSize * uint64(len(newRoots)-len(s.so.SectorRoots))
   257  		blocksRemaining := s.so.proofDeadline() - blockHeight
   258  		blockBytesCurrency := types.NewCurrency64(uint64(blocksRemaining)).Mul64(bytesAdded)
   259  		storageRevenue = settings.StoragePrice.Mul(blockBytesCurrency)
   260  		newCollateral = newCollateral.Add(settings.Collateral.Mul(blockBytesCurrency))
   261  	}
   262  
   263  	// If a Merkle proof was requested, construct it.
   264  	newMerkleRoot := cachedMerkleRoot(newRoots)
   265  	var merkleResp modules.LoopWriteMerkleProof
   266  	if req.MerkleProof {
   267  		// Calculate which sectors changed.
   268  		oldNumSectors := uint64(len(s.so.SectorRoots))
   269  		proofRanges := make([]crypto.ProofRange, 0, len(sectorsChanged))
   270  		for index := range sectorsChanged {
   271  			if index < oldNumSectors {
   272  				proofRanges = append(proofRanges, crypto.ProofRange{
   273  					Start: index,
   274  					End:   index + 1,
   275  				})
   276  			}
   277  		}
   278  		sort.Slice(proofRanges, func(i, j int) bool {
   279  			return proofRanges[i].Start < proofRanges[j].Start
   280  		})
   281  		// Record old leaf hashes for all changed sectors.
   282  		leafHashes := make([]crypto.Hash, len(proofRanges))
   283  		for i, r := range proofRanges {
   284  			leafHashes[i] = s.so.SectorRoots[r.Start]
   285  		}
   286  		// Construct the Merkle proof.
   287  		merkleResp = modules.LoopWriteMerkleProof{
   288  			OldSubtreeHashes: crypto.MerkleDiffProof(proofRanges, oldNumSectors, nil, s.so.SectorRoots),
   289  			OldLeafHashes:    leafHashes,
   290  			NewMerkleRoot:    newMerkleRoot,
   291  		}
   292  		// Calculate bandwidth cost of proof.
   293  		proofSize := crypto.HashSize * (len(merkleResp.OldSubtreeHashes) + len(leafHashes) + 1)
   294  		if proofSize < modules.RPCMinLen {
   295  			proofSize = modules.RPCMinLen
   296  		}
   297  		bandwidthRevenue = bandwidthRevenue.Add(settings.DownloadBandwidthPrice.Mul64(uint64(proofSize)))
   298  	}
   299  
   300  	// construct the new revision
   301  	newRevision := currentRevision
   302  	newRevision.NewRevisionNumber = req.NewRevisionNumber
   303  	for _, action := range req.Actions {
   304  		if action.Type == modules.WriteActionAppend {
   305  			newRevision.NewFileSize += modules.SectorSize
   306  		} else if action.Type == modules.WriteActionTrim {
   307  			newRevision.NewFileSize -= modules.SectorSize * action.A
   308  		}
   309  	}
   310  	newRevision.NewFileMerkleRoot = newMerkleRoot
   311  	newRevision.NewValidProofOutputs = make([]types.SiacoinOutput, len(currentRevision.NewValidProofOutputs))
   312  	for i := range newRevision.NewValidProofOutputs {
   313  		newRevision.NewValidProofOutputs[i] = types.SiacoinOutput{
   314  			Value:      req.NewValidProofValues[i],
   315  			UnlockHash: currentRevision.NewValidProofOutputs[i].UnlockHash,
   316  		}
   317  	}
   318  	newRevision.NewMissedProofOutputs = make([]types.SiacoinOutput, len(currentRevision.NewMissedProofOutputs))
   319  	for i := range newRevision.NewMissedProofOutputs {
   320  		newRevision.NewMissedProofOutputs[i] = types.SiacoinOutput{
   321  			Value:      req.NewMissedProofValues[i],
   322  			UnlockHash: currentRevision.NewMissedProofOutputs[i].UnlockHash,
   323  		}
   324  	}
   325  
   326  	// verify the new revision
   327  	newRevenue := settings.BaseRPCPrice.Add(storageRevenue).Add(bandwidthRevenue)
   328  	s.so.SectorRoots, newRoots = newRoots, s.so.SectorRoots // verifyRevision assumes new roots
   329  	err := verifyRevision(s.so, newRevision, blockHeight, newRevenue, newCollateral)
   330  	s.so.SectorRoots, newRoots = newRoots, s.so.SectorRoots
   331  	if err != nil {
   332  		s.writeError(err)
   333  		return err
   334  	}
   335  
   336  	// If a Merkle proof was requested, send it and wait for the renter's signature.
   337  	if req.MerkleProof {
   338  		if err := s.writeResponse(merkleResp); err != nil {
   339  			return err
   340  		} else if err := s.readResponse(&sigResponse, modules.RPCMinLen); err != nil {
   341  			return err
   342  		}
   343  	}
   344  
   345  	// Sign the new revision.
   346  	renterSig := types.TransactionSignature{
   347  		ParentID:       crypto.Hash(newRevision.ParentID),
   348  		CoveredFields:  types.CoveredFields{FileContractRevisions: []uint64{0}},
   349  		PublicKeyIndex: 0,
   350  		Signature:      sigResponse.Signature,
   351  	}
   352  	txn, err := createRevisionSignature(newRevision, renterSig, secretKey, blockHeight)
   353  	if err != nil {
   354  		s.writeError(err)
   355  		return err
   356  	}
   357  
   358  	// Update the storage obligation.
   359  	s.so.SectorRoots = newRoots
   360  	s.so.PotentialStorageRevenue = s.so.PotentialStorageRevenue.Add(storageRevenue)
   361  	s.so.RiskedCollateral = s.so.RiskedCollateral.Add(newCollateral)
   362  	s.so.PotentialUploadRevenue = s.so.PotentialUploadRevenue.Add(bandwidthRevenue)
   363  	s.so.RevisionTransactionSet = []types.Transaction{txn}
   364  	h.mu.Lock()
   365  	err = h.modifyStorageObligation(s.so, sectorsRemoved, sectorsGained, gainedSectorData)
   366  	h.mu.Unlock()
   367  	if err != nil {
   368  		s.writeError(err)
   369  		return err
   370  	}
   371  
   372  	// Send the response.
   373  	resp := modules.LoopWriteResponse{
   374  		Signature: txn.TransactionSignatures[1].Signature,
   375  	}
   376  	if err := s.writeResponse(resp); err != nil {
   377  		return err
   378  	}
   379  	return nil
   380  }
   381  
   382  // managedRPCLoopRead writes an RPC response containing the requested data
   383  // (along with signatures and an optional Merkle proof).
   384  func (h *Host) managedRPCLoopRead(s *rpcSession) error {
   385  	s.extendDeadline(modules.NegotiateDownloadTime)
   386  
   387  	// Read the request.
   388  	var req modules.LoopReadRequest
   389  	if err := s.readRequest(&req, modules.RPCMinLen); err != nil {
   390  		// Reading may have failed due to a closed connection; regardless, it
   391  		// doesn't hurt to try and tell the renter about it.
   392  		s.writeError(err)
   393  		return err
   394  	}
   395  
   396  	// As soon as we finish reading the request, we must begin listening for
   397  	// RPCLoopReadStop, which may arrive at any time, and must arrive before the
   398  	// RPC is considered complete.
   399  	stopSignal := make(chan error, 1)
   400  	go func() {
   401  		var id types.Specifier
   402  		err := s.readResponse(&id, modules.RPCMinLen)
   403  		if err != nil {
   404  			stopSignal <- err
   405  		} else if id != modules.RPCLoopReadStop {
   406  			stopSignal <- errors.New("expected 'stop' from renter, got " + id.String())
   407  		} else {
   408  			stopSignal <- nil
   409  		}
   410  	}()
   411  
   412  	// Check that a contract is locked.
   413  	if len(s.so.OriginTransactionSet) == 0 {
   414  		err := errors.New("no contract locked")
   415  		s.writeError(err)
   416  		<-stopSignal
   417  		return err
   418  	}
   419  
   420  	// Read some internal fields for later.
   421  	h.mu.Lock()
   422  	blockHeight := h.blockHeight
   423  	secretKey := h.secretKey
   424  	settings := h.externalSettings()
   425  	h.mu.Unlock()
   426  	currentRevision := s.so.RevisionTransactionSet[len(s.so.RevisionTransactionSet)-1].FileContractRevisions[0]
   427  
   428  	// Validate the request.
   429  	for _, sec := range req.Sections {
   430  		var err error
   431  		switch {
   432  		case uint64(sec.Offset)+uint64(sec.Length) > modules.SectorSize:
   433  			err = errRequestOutOfBounds
   434  		case sec.Length == 0:
   435  			err = errors.New("length cannot be zero")
   436  		case req.MerkleProof && (sec.Offset%crypto.SegmentSize != 0 || sec.Length%crypto.SegmentSize != 0):
   437  			err = errors.New("offset and length must be multiples of SegmentSize when requesting a Merkle proof")
   438  		case len(req.NewValidProofValues) != len(currentRevision.NewValidProofOutputs):
   439  			err = errors.New("wrong number of valid proof values")
   440  		case len(req.NewMissedProofValues) != len(currentRevision.NewMissedProofOutputs):
   441  			err = errors.New("wrong number of missed proof values")
   442  		}
   443  		if err != nil {
   444  			s.writeError(err)
   445  			return err
   446  		}
   447  	}
   448  
   449  	// construct the new revision
   450  	newRevision := currentRevision
   451  	newRevision.NewRevisionNumber = req.NewRevisionNumber
   452  	newRevision.NewValidProofOutputs = make([]types.SiacoinOutput, len(currentRevision.NewValidProofOutputs))
   453  	for i := range newRevision.NewValidProofOutputs {
   454  		newRevision.NewValidProofOutputs[i] = types.SiacoinOutput{
   455  			Value:      req.NewValidProofValues[i],
   456  			UnlockHash: currentRevision.NewValidProofOutputs[i].UnlockHash,
   457  		}
   458  	}
   459  	newRevision.NewMissedProofOutputs = make([]types.SiacoinOutput, len(currentRevision.NewMissedProofOutputs))
   460  	for i := range newRevision.NewMissedProofOutputs {
   461  		newRevision.NewMissedProofOutputs[i] = types.SiacoinOutput{
   462  			Value:      req.NewMissedProofValues[i],
   463  			UnlockHash: currentRevision.NewMissedProofOutputs[i].UnlockHash,
   464  		}
   465  	}
   466  
   467  	// calculate expected cost and verify against renter's revision
   468  	var estBandwidth uint64
   469  	sectorAccesses := make(map[crypto.Hash]struct{})
   470  	for _, sec := range req.Sections {
   471  		// use the worst-case proof size of 2*tree depth (this occurs when
   472  		// proving across the two leaves in the center of the tree)
   473  		estHashesPerProof := 2 * bits.Len64(modules.SectorSize/crypto.SegmentSize)
   474  		estBandwidth += uint64(sec.Length) + uint64(estHashesPerProof*crypto.HashSize)
   475  		sectorAccesses[sec.MerkleRoot] = struct{}{}
   476  	}
   477  	if estBandwidth < modules.RPCMinLen {
   478  		estBandwidth = modules.RPCMinLen
   479  	}
   480  	bandwidthCost := settings.DownloadBandwidthPrice.Mul64(estBandwidth)
   481  	sectorAccessCost := settings.SectorAccessPrice.Mul64(uint64(len(sectorAccesses)))
   482  	totalCost := settings.BaseRPCPrice.Add(bandwidthCost).Add(sectorAccessCost)
   483  	err := verifyPaymentRevision(currentRevision, newRevision, blockHeight, totalCost)
   484  	if err != nil {
   485  		s.writeError(err)
   486  		return err
   487  	}
   488  
   489  	// Sign the new revision.
   490  	renterSig := types.TransactionSignature{
   491  		ParentID:       crypto.Hash(newRevision.ParentID),
   492  		CoveredFields:  types.CoveredFields{FileContractRevisions: []uint64{0}},
   493  		PublicKeyIndex: 0,
   494  		Signature:      req.Signature,
   495  	}
   496  	txn, err := createRevisionSignature(newRevision, renterSig, secretKey, blockHeight)
   497  	if err != nil {
   498  		s.writeError(err)
   499  		return err
   500  	}
   501  	hostSig := txn.TransactionSignatures[1].Signature
   502  
   503  	// Update the storage obligation.
   504  	paymentTransfer := currentRevision.NewValidProofOutputs[0].Value.Sub(newRevision.NewValidProofOutputs[0].Value)
   505  	s.so.PotentialDownloadRevenue = s.so.PotentialDownloadRevenue.Add(paymentTransfer)
   506  	s.so.RevisionTransactionSet = []types.Transaction{txn}
   507  	h.mu.Lock()
   508  	err = h.modifyStorageObligation(s.so, nil, nil, nil)
   509  	h.mu.Unlock()
   510  	if err != nil {
   511  		s.writeError(err)
   512  		return err
   513  	}
   514  
   515  	// enter response loop
   516  	for i, sec := range req.Sections {
   517  		// Fetch the requested data.
   518  		sectorData, err := h.ReadSector(sec.MerkleRoot)
   519  		if err != nil {
   520  			s.writeError(err)
   521  			return err
   522  		}
   523  		data := sectorData[sec.Offset : sec.Offset+sec.Length]
   524  
   525  		// Construct the Merkle proof, if requested.
   526  		var proof []crypto.Hash
   527  		if req.MerkleProof {
   528  			proofStart := int(sec.Offset) / crypto.SegmentSize
   529  			proofEnd := int(sec.Offset+sec.Length) / crypto.SegmentSize
   530  			proof = crypto.MerkleRangeProof(sectorData, proofStart, proofEnd)
   531  		}
   532  
   533  		// Send the response. If the renter sent a stop signal, or this is the
   534  		// final response, include our signature in the response.
   535  		resp := modules.LoopReadResponse{
   536  			Signature:   nil,
   537  			Data:        data,
   538  			MerkleProof: proof,
   539  		}
   540  		select {
   541  		case err := <-stopSignal:
   542  			if err != nil {
   543  				return err
   544  			}
   545  			resp.Signature = hostSig
   546  			return s.writeResponse(resp)
   547  		default:
   548  		}
   549  		if i == len(req.Sections)-1 {
   550  			resp.Signature = hostSig
   551  		}
   552  		if err := s.writeResponse(resp); err != nil {
   553  			return err
   554  		}
   555  	}
   556  	// The stop signal must arrive before RPC is complete.
   557  	return <-stopSignal
   558  }
   559  
   560  // managedRPCLoopFormContract handles the contract formation RPC.
   561  func (h *Host) managedRPCLoopFormContract(s *rpcSession) error {
   562  	// NOTE: this RPC contains two request/response exchanges.
   563  	s.extendDeadline(modules.NegotiateFileContractTime)
   564  
   565  	// Read the contract request.
   566  	var req modules.LoopFormContractRequest
   567  	if err := s.readRequest(&req, modules.TransactionSetSizeLimit); err != nil {
   568  		s.writeError(err)
   569  		return err
   570  	}
   571  
   572  	h.mu.Lock()
   573  	settings := h.externalSettings()
   574  	h.mu.Unlock()
   575  	if !settings.AcceptingContracts {
   576  		s.writeError(errors.New("host is not accepting new contracts"))
   577  		return nil
   578  	}
   579  
   580  	// The host verifies that the file contract coming over the wire is
   581  	// acceptable.
   582  	txnSet := req.Transactions
   583  	var renterPK crypto.PublicKey
   584  	copy(renterPK[:], req.RenterKey.Key)
   585  	if err := h.managedVerifyNewContract(txnSet, renterPK, settings); err != nil {
   586  		s.writeError(err)
   587  		return err
   588  	}
   589  	// The host adds collateral to the transaction.
   590  	txnBuilder, newParents, newInputs, newOutputs, err := h.managedAddCollateral(settings, txnSet)
   591  	if err != nil {
   592  		s.writeError(err)
   593  		return err
   594  	}
   595  	// Send any new inputs and outputs that were added to the transaction.
   596  	resp := modules.LoopContractAdditions{
   597  		Parents: newParents,
   598  		Inputs:  newInputs,
   599  		Outputs: newOutputs,
   600  	}
   601  	if err := s.writeResponse(resp); err != nil {
   602  		return err
   603  	}
   604  
   605  	// The renter will now send transaction signatures for the file contract
   606  	// transaction and a signature for the implicit no-op file contract
   607  	// revision.
   608  	var renterSigs modules.LoopContractSignatures
   609  	if err := s.readResponse(&renterSigs, modules.RPCMinLen); err != nil {
   610  		s.writeError(err)
   611  		return err
   612  	}
   613  
   614  	// The host adds the renter transaction signatures, then signs the
   615  	// transaction and submits it to the blockchain, creating a storage
   616  	// obligation in the process.
   617  	h.mu.RLock()
   618  	hostCollateral := contractCollateral(settings, txnSet[len(txnSet)-1].FileContracts[0])
   619  	h.mu.RUnlock()
   620  	hostTxnSignatures, hostRevisionSignature, newSOID, err := h.managedFinalizeContract(txnBuilder, renterPK, renterSigs.ContractSignatures, renterSigs.RevisionSignature, nil, hostCollateral, types.ZeroCurrency, types.ZeroCurrency, settings)
   621  	if err != nil {
   622  		s.writeError(err)
   623  		return err
   624  	}
   625  	defer h.managedUnlockStorageObligation(newSOID)
   626  
   627  	// Send our signatures for the contract transaction and initial revision.
   628  	hostSigs := modules.LoopContractSignatures{
   629  		ContractSignatures: hostTxnSignatures,
   630  		RevisionSignature:  hostRevisionSignature,
   631  	}
   632  	if err := s.writeResponse(hostSigs); err != nil {
   633  		return err
   634  	}
   635  
   636  	return nil
   637  }
   638  
   639  // managedRPCLoopRenewContract handles the LoopRenewContract RPC.
   640  func (h *Host) managedRPCLoopRenewContract(s *rpcSession) error {
   641  	// NOTE: this RPC contains two request/response exchanges.
   642  	s.extendDeadline(modules.NegotiateRenewContractTime)
   643  
   644  	// Read the renewal request.
   645  	var req modules.LoopRenewContractRequest
   646  	if err := s.readRequest(&req, modules.TransactionSetSizeLimit); err != nil {
   647  		s.writeError(err)
   648  		return err
   649  	}
   650  
   651  	h.mu.Lock()
   652  	settings := h.externalSettings()
   653  	h.mu.Unlock()
   654  	if !settings.AcceptingContracts {
   655  		s.writeError(errors.New("host is not accepting new contracts"))
   656  		return nil
   657  	} else if len(s.so.RevisionTransactionSet) == 0 {
   658  		err := errors.New("no such contract")
   659  		s.writeError(err)
   660  		return err
   661  	}
   662  
   663  	// Verify that the transaction coming over the wire is a proper renewal.
   664  	var renterPK crypto.PublicKey
   665  	copy(renterPK[:], req.RenterKey.Key)
   666  	err := h.managedVerifyRenewedContract(s.so, req.Transactions, renterPK)
   667  	if err != nil {
   668  		s.writeError(err)
   669  		return extendErr("verification of renewal failed: ", err)
   670  	}
   671  	txnBuilder, newParents, newInputs, newOutputs, err := h.managedAddRenewCollateral(s.so, settings, req.Transactions)
   672  	if err != nil {
   673  		s.writeError(err)
   674  		return extendErr("failed to add collateral: ", err)
   675  	}
   676  	// Send any new inputs and outputs that were added to the transaction.
   677  	resp := modules.LoopContractAdditions{
   678  		Parents: newParents,
   679  		Inputs:  newInputs,
   680  		Outputs: newOutputs,
   681  	}
   682  	if err := s.writeResponse(resp); err != nil {
   683  		return err
   684  	}
   685  
   686  	// The renter will now send transaction signatures for the file contract
   687  	// transaction and a signature for the implicit no-op file contract
   688  	// revision.
   689  	var renterSigs modules.LoopContractSignatures
   690  	if err := s.readResponse(&renterSigs, modules.RPCMinLen); err != nil {
   691  		s.writeError(err)
   692  		return err
   693  	}
   694  
   695  	// The host adds the renter transaction signatures, then signs the
   696  	// transaction and submits it to the blockchain, creating a storage
   697  	// obligation in the process.
   698  	h.mu.RLock()
   699  	fc := req.Transactions[len(req.Transactions)-1].FileContracts[0]
   700  	renewCollateral := renewContractCollateral(s.so, settings, fc)
   701  	renewRevenue := renewBasePrice(s.so, settings, fc)
   702  	renewRisk := renewBaseCollateral(s.so, settings, fc)
   703  	h.mu.RUnlock()
   704  	hostTxnSignatures, hostRevisionSignature, newSOID, err := h.managedFinalizeContract(txnBuilder, renterPK, renterSigs.ContractSignatures, renterSigs.RevisionSignature, s.so.SectorRoots, renewCollateral, renewRevenue, renewRisk, settings)
   705  	if err != nil {
   706  		s.writeError(err)
   707  		return extendErr("failed to finalize contract: ", err)
   708  	}
   709  	defer h.managedUnlockStorageObligation(newSOID)
   710  
   711  	// Send our signatures for the contract transaction and initial revision.
   712  	hostSigs := modules.LoopContractSignatures{
   713  		ContractSignatures: hostTxnSignatures,
   714  		RevisionSignature:  hostRevisionSignature,
   715  	}
   716  	if err := s.writeResponse(hostSigs); err != nil {
   717  		return err
   718  	}
   719  
   720  	return nil
   721  }
   722  
   723  // managedRPCLoopSectorRoots writes an RPC response containing the requested
   724  // contract roots (along with signatures and a Merkle proof).
   725  func (h *Host) managedRPCLoopSectorRoots(s *rpcSession) error {
   726  	s.extendDeadline(modules.NegotiateDownloadTime)
   727  
   728  	// Read the request.
   729  	var req modules.LoopSectorRootsRequest
   730  	if err := s.readRequest(&req, modules.RPCMinLen); err != nil {
   731  		// Reading may have failed due to a closed connection; regardless, it
   732  		// doesn't hurt to try and tell the renter about it.
   733  		s.writeError(err)
   734  		return err
   735  	}
   736  
   737  	// Check that a contract is locked.
   738  	if len(s.so.OriginTransactionSet) == 0 {
   739  		err := errors.New("no contract locked")
   740  		s.writeError(err)
   741  		return err
   742  	}
   743  
   744  	// Read some internal fields for later.
   745  	h.mu.Lock()
   746  	blockHeight := h.blockHeight
   747  	secretKey := h.secretKey
   748  	settings := h.externalSettings()
   749  	h.mu.Unlock()
   750  	currentRevision := s.so.RevisionTransactionSet[len(s.so.RevisionTransactionSet)-1].FileContractRevisions[0]
   751  
   752  	// Validate the request.
   753  	var err error
   754  	if req.NumRoots > settings.MaxDownloadBatchSize/crypto.HashSize {
   755  		err = errLargeDownloadBatch
   756  	}
   757  	if req.RootOffset > uint64(len(s.so.SectorRoots)) || req.RootOffset+req.NumRoots > uint64(len(s.so.SectorRoots)) {
   758  		err = errRequestOutOfBounds
   759  	} else if len(req.NewValidProofValues) != len(currentRevision.NewValidProofOutputs) {
   760  		err = errors.New("wrong number of valid proof values")
   761  	} else if len(req.NewMissedProofValues) != len(currentRevision.NewMissedProofOutputs) {
   762  		err = errors.New("wrong number of missed proof values")
   763  	}
   764  	if err != nil {
   765  		s.writeError(err)
   766  		return extendErr("download iteration request failed: ", err)
   767  	}
   768  
   769  	// Fetch the roots and construct the Merkle proof
   770  	contractRoots := s.so.SectorRoots[req.RootOffset:][:req.NumRoots]
   771  	proofStart := int(req.RootOffset)
   772  	proofEnd := int(req.RootOffset + req.NumRoots)
   773  	proof := crypto.MerkleSectorRangeProof(s.so.SectorRoots, proofStart, proofEnd)
   774  
   775  	// construct the new revision
   776  	newRevision := currentRevision
   777  	newRevision.NewRevisionNumber = req.NewRevisionNumber
   778  	newRevision.NewValidProofOutputs = make([]types.SiacoinOutput, len(currentRevision.NewValidProofOutputs))
   779  	for i := range newRevision.NewValidProofOutputs {
   780  		newRevision.NewValidProofOutputs[i] = types.SiacoinOutput{
   781  			Value:      req.NewValidProofValues[i],
   782  			UnlockHash: currentRevision.NewValidProofOutputs[i].UnlockHash,
   783  		}
   784  	}
   785  	newRevision.NewMissedProofOutputs = make([]types.SiacoinOutput, len(currentRevision.NewMissedProofOutputs))
   786  	for i := range newRevision.NewMissedProofOutputs {
   787  		newRevision.NewMissedProofOutputs[i] = types.SiacoinOutput{
   788  			Value:      req.NewMissedProofValues[i],
   789  			UnlockHash: currentRevision.NewMissedProofOutputs[i].UnlockHash,
   790  		}
   791  	}
   792  
   793  	// calculate expected cost and verify against renter's revision
   794  	responseSize := (req.NumRoots + uint64(len(proof))) * crypto.HashSize
   795  	if responseSize < modules.RPCMinLen {
   796  		responseSize = modules.RPCMinLen
   797  	}
   798  	bandwidthCost := settings.DownloadBandwidthPrice.Mul64(responseSize)
   799  	totalCost := settings.BaseRPCPrice.Add(bandwidthCost)
   800  	err = verifyPaymentRevision(currentRevision, newRevision, blockHeight, totalCost)
   801  	if err != nil {
   802  		s.writeError(err)
   803  		return extendErr("payment validation failed: ", err)
   804  	}
   805  
   806  	// Sign the new revision.
   807  	renterSig := types.TransactionSignature{
   808  		ParentID:       crypto.Hash(newRevision.ParentID),
   809  		CoveredFields:  types.CoveredFields{FileContractRevisions: []uint64{0}},
   810  		PublicKeyIndex: 0,
   811  		Signature:      req.Signature,
   812  	}
   813  	txn, err := createRevisionSignature(newRevision, renterSig, secretKey, blockHeight)
   814  	if err != nil {
   815  		s.writeError(err)
   816  		return extendErr("failed to create revision signature: ", err)
   817  	}
   818  
   819  	// Update the storage obligation.
   820  	paymentTransfer := currentRevision.NewValidProofOutputs[0].Value.Sub(newRevision.NewValidProofOutputs[0].Value)
   821  	s.so.PotentialDownloadRevenue = s.so.PotentialDownloadRevenue.Add(paymentTransfer)
   822  	s.so.RevisionTransactionSet = []types.Transaction{txn}
   823  	h.mu.Lock()
   824  	err = h.modifyStorageObligation(s.so, nil, nil, nil)
   825  	h.mu.Unlock()
   826  	if err != nil {
   827  		s.writeError(err)
   828  		return extendErr("failed to modify storage obligation: ", err)
   829  	}
   830  
   831  	// send the response
   832  	resp := modules.LoopSectorRootsResponse{
   833  		Signature:   txn.TransactionSignatures[1].Signature,
   834  		SectorRoots: contractRoots,
   835  		MerkleProof: proof,
   836  	}
   837  	if err := s.writeResponse(resp); err != nil {
   838  		return err
   839  	}
   840  	return nil
   841  }