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 }