From f72797bc75384d5d70550cf11437d916c52d96ac Mon Sep 17 00:00:00 2001 From: Nate Maninger Date: Mon, 21 Oct 2024 10:03:09 -0700 Subject: [PATCH 01/16] rhp4: implement rpc changes --- rhp/v4/encoding.go | 75 +++++++++-------------------- rhp/v4/merkle.go | 3 ++ rhp/v4/rhp.go | 111 +++++++++++++------------------------------ rhp/v4/validation.go | 10 ++-- 4 files changed, 65 insertions(+), 134 deletions(-) diff --git a/rhp/v4/encoding.go b/rhp/v4/encoding.go index 35278e21..efed35b5 100644 --- a/rhp/v4/encoding.go +++ b/rhp/v4/encoding.go @@ -2,7 +2,6 @@ package rhp import ( "bytes" - "fmt" "go.sia.tech/core/types" ) @@ -26,7 +25,7 @@ func (hp HostPrices) EncodeTo(e *types.Encoder) { types.V2Currency(hp.StoragePrice).EncodeTo(e) types.V2Currency(hp.IngressPrice).EncodeTo(e) types.V2Currency(hp.EgressPrice).EncodeTo(e) - types.V2Currency(hp.ModifySectorActionPrice).EncodeTo(e) + types.V2Currency(hp.RemoveSectorPrice).EncodeTo(e) e.WriteUint64(hp.TipHeight) e.WriteTime(hp.ValidUntil) hp.Signature.EncodeTo(e) @@ -39,7 +38,7 @@ func (hp *HostPrices) DecodeFrom(d *types.Decoder) { (*types.V2Currency)(&hp.StoragePrice).DecodeFrom(d) (*types.V2Currency)(&hp.IngressPrice).DecodeFrom(d) (*types.V2Currency)(&hp.EgressPrice).DecodeFrom(d) - (*types.V2Currency)(&hp.ModifySectorActionPrice).DecodeFrom(d) + (*types.V2Currency)(&hp.RemoveSectorPrice).DecodeFrom(d) hp.TipHeight = d.ReadUint64() hp.ValidUntil = d.ReadTime() hp.Signature.DecodeFrom(d) @@ -54,7 +53,7 @@ func (hs HostSettings) EncodeTo(e *types.Encoder) { types.V2Currency(hs.MaxCollateral).EncodeTo(e) e.WriteUint64(hs.MaxContractDuration) e.WriteUint64(hs.MaxSectorDuration) - e.WriteUint64(hs.MaxModifyActions) + e.WriteUint64(hs.MaxSectorBatchSize) e.WriteUint64(hs.RemainingStorage) e.WriteUint64(hs.TotalStorage) hs.Prices.EncodeTo(e) @@ -69,46 +68,12 @@ func (hs *HostSettings) DecodeFrom(d *types.Decoder) { (*types.V2Currency)(&hs.MaxCollateral).DecodeFrom(d) hs.MaxContractDuration = d.ReadUint64() hs.MaxSectorDuration = d.ReadUint64() - hs.MaxModifyActions = d.ReadUint64() + hs.MaxSectorBatchSize = d.ReadUint64() hs.RemainingStorage = d.ReadUint64() hs.TotalStorage = d.ReadUint64() hs.Prices.DecodeFrom(d) } -// EncodeTo implements types.EncoderTo. -func (m ModifyAction) EncodeTo(e *types.Encoder) { - e.WriteUint8(m.Type) - switch m.Type { - case ActionSwap: - e.WriteUint64(m.A) - e.WriteUint64(m.B) - case ActionTrim: - e.WriteUint64(m.N) - case ActionUpdate: - m.Root.EncodeTo(e) - e.WriteUint64(m.A) - default: - panic("invalid action type") - } -} - -// DecodeFrom implements types.DecoderFrom. -func (m *ModifyAction) DecodeFrom(d *types.Decoder) { - m.Type = d.ReadUint8() - switch m.Type { - case ActionSwap: - m.A = d.ReadUint64() - m.B = d.ReadUint64() - case ActionTrim: - m.N = d.ReadUint64() - case ActionUpdate: - m.Root.DecodeFrom(d) - m.A = d.ReadUint64() - default: - d.SetErr(fmt.Errorf("invalid action type (%v)", m.Type)) - } -} - // EncodeTo implements types.EncoderTo. func (a Account) EncodeTo(e *types.Encoder) { e.Write(a[:]) } @@ -389,53 +354,57 @@ func (r *RPCRefreshContractThirdResponse) maxLen() int { return reasonableObjectSize } -func (r *RPCModifySectorsRequest) encodeTo(e *types.Encoder) { +func (r *RPCRemoveSectorsRequest) encodeTo(e *types.Encoder) { r.ContractID.EncodeTo(e) r.Prices.EncodeTo(e) - types.EncodeSlice(e, r.Actions) + types.EncodeSliceFn(e, r.Indices, func(e *types.Encoder, v uint64) { + e.WriteUint64(v) + }) r.ChallengeSignature.EncodeTo(e) } -func (r *RPCModifySectorsRequest) decodeFrom(d *types.Decoder) { +func (r *RPCRemoveSectorsRequest) decodeFrom(d *types.Decoder) { r.ContractID.DecodeFrom(d) r.Prices.DecodeFrom(d) - types.DecodeSlice(d, &r.Actions) + types.DecodeSliceFn(d, &r.Indices, func(d *types.Decoder) uint64 { + return d.ReadUint64() + }) r.ChallengeSignature.DecodeFrom(d) } -func (r *RPCModifySectorsRequest) maxLen() int { +func (r *RPCRemoveSectorsRequest) maxLen() int { return reasonableObjectSize } -func (r *RPCModifySectorsResponse) encodeTo(e *types.Encoder) { +func (r *RPCRemoveSectorsResponse) encodeTo(e *types.Encoder) { types.EncodeSlice(e, r.OldSubtreeHashes) types.EncodeSlice(e, r.OldLeafHashes) r.NewMerkleRoot.EncodeTo(e) } -func (r *RPCModifySectorsResponse) decodeFrom(d *types.Decoder) { +func (r *RPCRemoveSectorsResponse) decodeFrom(d *types.Decoder) { types.DecodeSlice(d, &r.OldSubtreeHashes) types.DecodeSlice(d, &r.OldLeafHashes) r.NewMerkleRoot.DecodeFrom(d) } -func (r *RPCModifySectorsResponse) maxLen() int { +func (r *RPCRemoveSectorsResponse) maxLen() int { return reasonableObjectSize } -func (r *RPCModifySectorsSecondResponse) encodeTo(e *types.Encoder) { +func (r *RPCRemoveSectorsSecondResponse) encodeTo(e *types.Encoder) { r.RenterSignature.EncodeTo(e) } -func (r *RPCModifySectorsSecondResponse) decodeFrom(d *types.Decoder) { +func (r *RPCRemoveSectorsSecondResponse) decodeFrom(d *types.Decoder) { r.RenterSignature.DecodeFrom(d) } -func (r *RPCModifySectorsSecondResponse) maxLen() int { +func (r *RPCRemoveSectorsSecondResponse) maxLen() int { return sizeofSignature } -func (r *RPCModifySectorsThirdResponse) encodeTo(e *types.Encoder) { +func (r *RPCRemoveSectorsThirdResponse) encodeTo(e *types.Encoder) { r.HostSignature.EncodeTo(e) } -func (r *RPCModifySectorsThirdResponse) decodeFrom(d *types.Decoder) { +func (r *RPCRemoveSectorsThirdResponse) decodeFrom(d *types.Decoder) { r.HostSignature.DecodeFrom(d) } -func (r *RPCModifySectorsThirdResponse) maxLen() int { +func (r *RPCRemoveSectorsThirdResponse) maxLen() int { return sizeofSignature } diff --git a/rhp/v4/merkle.go b/rhp/v4/merkle.go index ca381815..a171fedd 100644 --- a/rhp/v4/merkle.go +++ b/rhp/v4/merkle.go @@ -106,6 +106,8 @@ func VerifySectorRootsProof(proof, sectorRoots []types.Hash256, numSectors, star return rhp2.VerifySectorRangeProof(proof, sectorRoots, start, end, numSectors, root) } +/* +TODO: implement for RPC remove func convertActions(actions []ModifyAction) []rhp2.RPCWriteAction { rhp2Actions := make([]rhp2.RPCWriteAction, len(actions)) for i, a := range actions { @@ -142,3 +144,4 @@ func BuildModifySectorsProof(actions []ModifyAction, sectorRoots []types.Hash256 func VerifyModifySectorsProof(actions []ModifyAction, numSectors uint64, treeHashes, leafHashes []types.Hash256, oldRoot types.Hash256, newRoot types.Hash256) bool { return rhp2.VerifyDiffProof(convertActions(actions), numSectors, treeHashes, leafHashes, oldRoot, newRoot, nil) } +*/ diff --git a/rhp/v4/rhp.go b/rhp/v4/rhp.go index 6d4a80eb..f2e73410 100644 --- a/rhp/v4/rhp.go +++ b/rhp/v4/rhp.go @@ -25,7 +25,7 @@ var ( RPCFundAccountsID = types.NewSpecifier("FundAccounts") RPCLatestRevisionID = types.NewSpecifier("LatestRevision") RPCAppendSectorsID = types.NewSpecifier("AppendSectors") - RPCModifySectorsID = types.NewSpecifier("ModifySectors") + RPCRemoveSectorsID = types.NewSpecifier("RemoveSectors") RPCReadSectorID = types.NewSpecifier("ReadSector") RPCRenewContractID = types.NewSpecifier("RenewContract") RPCRefreshContractID = types.NewSpecifier("RefreshContract") @@ -42,14 +42,14 @@ func round4KiB(n uint64) uint64 { // HostPrices specify a time-bound set of parameters used to calculate the cost // of various RPCs. type HostPrices struct { - ContractPrice types.Currency `json:"contractPrice"` - Collateral types.Currency `json:"collateral"` - StoragePrice types.Currency `json:"storagePrice"` - IngressPrice types.Currency `json:"ingressPrice"` - EgressPrice types.Currency `json:"egressPrice"` - ModifySectorActionPrice types.Currency `json:"modifySectorActionPrice"` - TipHeight uint64 `json:"tipHeight"` - ValidUntil time.Time `json:"validUntil"` + ContractPrice types.Currency `json:"contractPrice"` + Collateral types.Currency `json:"collateral"` + StoragePrice types.Currency `json:"storagePrice"` + IngressPrice types.Currency `json:"ingressPrice"` + EgressPrice types.Currency `json:"egressPrice"` + RemoveSectorPrice types.Currency `json:"removeSectorPrice"` + TipHeight uint64 `json:"tipHeight"` + ValidUntil time.Time `json:"validUntil"` // covers above fields Signature types.Signature `json:"signature"` @@ -85,19 +85,11 @@ func (hp HostPrices) RPCVerifySectorCost() types.Currency { return hp.EgressPrice.Mul64(SectorSize) } -// RPCModifySectorsCost returns the cost of modifying a contract's sectors with the +// RPCRemoveSectorsCost returns the cost of modifying a contract's sectors with the // given actions. The duration parameter is the number of blocks until the // contract's expiration height. -func (hp HostPrices) RPCModifySectorsCost(actions []ModifyAction) (cost types.Currency) { - var n uint64 - for _, action := range actions { - if action.Type == ActionTrim { - n += action.N - } else { - n++ - } - } - return hp.ModifySectorActionPrice.Mul64(n) +func (hp HostPrices) RPCRemoveSectorsCost(sectors int) (cost types.Currency) { + return hp.RemoveSectorPrice.Mul64(uint64(sectors)) } // RPCAppendSectorsCost returns the cost of appending sectors to a contract. The duration @@ -117,7 +109,7 @@ func (hp HostPrices) SigHash() types.Hash256 { types.V2Currency(hp.StoragePrice).EncodeTo(h.E) types.V2Currency(hp.IngressPrice).EncodeTo(h.E) types.V2Currency(hp.EgressPrice).EncodeTo(h.E) - types.V2Currency(hp.ModifySectorActionPrice).EncodeTo(h.E) + types.V2Currency(hp.RemoveSectorPrice).EncodeTo(h.E) h.E.WriteUint64(hp.TipHeight) h.E.WriteTime(hp.ValidUntil) return h.Sum() @@ -144,28 +136,12 @@ type HostSettings struct { MaxCollateral types.Currency `json:"maxCollateral"` MaxContractDuration uint64 `json:"maxContractDuration"` MaxSectorDuration uint64 `json:"maxSectorDuration"` - MaxModifyActions uint64 `json:"maxModifyActions"` + MaxSectorBatchSize uint64 `json:"maxSectorBatchSize"` RemainingStorage uint64 `json:"remainingStorage"` TotalStorage uint64 `json:"totalStorage"` Prices HostPrices `json:"prices"` } -// A ModifyAction adds or modifies sectors within a contract. -type ModifyAction struct { - Type uint8 `json:"type"` - Root types.Hash256 `json:"root,omitempty"` // Update - A uint64 `json:"a,omitempty"` // Swap - B uint64 `json:"b,omitempty"` // Swap - N uint64 `json:"n,omitempty"` // Trim, Update -} - -// ModifyAction types. -const ( - ActionSwap = iota + 1 - ActionTrim - ActionUpdate -) - // An Account represents an ephemeral balance that can be funded via contract // revision and spent to pay for RPCs. type Account types.PublicKey @@ -333,26 +309,26 @@ type ( TransactionSet []types.V2Transaction `json:"transactionSet"` } - // RPCModifySectorsRequest implements Object. - RPCModifySectorsRequest struct { + // RPCRemoveSectorsRequest implements Object. + RPCRemoveSectorsRequest struct { ContractID types.FileContractID `json:"contractID"` Prices HostPrices `json:"prices"` - Actions []ModifyAction `json:"actions"` + Indices []uint64 `json:"indices"` // A ChallengeSignature proves the renter can modify the contract. ChallengeSignature types.Signature `json:"challengeSignature"` } - // RPCModifySectorsResponse implements Object. - RPCModifySectorsResponse struct { + // RPCRemoveSectorsResponse implements Object. + RPCRemoveSectorsResponse struct { OldSubtreeHashes []types.Hash256 `json:"oldSubtreeHashes"` OldLeafHashes []types.Hash256 `json:"oldLeafHashes"` NewMerkleRoot types.Hash256 `json:"newMerkleRoot"` } - // RPCModifySectorsSecondResponse implements Object. - RPCModifySectorsSecondResponse struct { + // RPCRemoveSectorsSecondResponse implements Object. + RPCRemoveSectorsSecondResponse struct { RenterSignature types.Signature `json:"renterSignature"` } - // RPCModifySectorsThirdResponse implements Object. - RPCModifySectorsThirdResponse struct { + // RPCRemoveSectorsThirdResponse implements Object. + RPCRemoveSectorsThirdResponse struct { HostSignature types.Signature `json:"hostSignature"` } @@ -488,7 +464,7 @@ type ( // ChallengeSigHash returns the hash of the challenge signature used for // signing. -func (r *RPCModifySectorsRequest) ChallengeSigHash(revisionNumber uint64) types.Hash256 { +func (r *RPCRemoveSectorsRequest) ChallengeSigHash(revisionNumber uint64) types.Hash256 { h := types.NewHasher() r.ContractID.EncodeTo(h.E) h.E.WriteUint64(revisionNumber) @@ -496,7 +472,7 @@ func (r *RPCModifySectorsRequest) ChallengeSigHash(revisionNumber uint64) types. } // ValidChallengeSignature checks the challenge signature for validity. -func (r *RPCModifySectorsRequest) ValidChallengeSignature(fc types.V2FileContract) bool { +func (r *RPCRemoveSectorsRequest) ValidChallengeSignature(fc types.V2FileContract) bool { return fc.RenterPublicKey.VerifyHash(r.ChallengeSigHash(fc.RevisionNumber+1), r.ChallengeSignature) } @@ -542,26 +518,6 @@ func (r *RPCRefreshContractRequest) ValidChallengeSignature(existing types.V2Fil return existing.RenterPublicKey.VerifyHash(r.ChallengeSigHash(existing.RevisionNumber), r.ChallengeSignature) } -// ValidateModifyActions checks the given actions for validity. It returns an -// error if the actions are invalid. -func ValidateModifyActions(actions []ModifyAction, maxActions uint64) error { - var actionCount uint64 - for _, action := range actions { - switch action.Type { - case ActionSwap, ActionUpdate: - actionCount++ - case ActionTrim: - actionCount += action.N - default: - return fmt.Errorf("invalid action type: %v", action.Type) - } - } - if actionCount > maxActions { - return fmt.Errorf("too many actions: %v > %v", actionCount, maxActions) - } - return nil -} - // NewContract creates a new file contract with the given settings. func NewContract(p HostPrices, cp RPCFormContractParams, hostKey types.PublicKey, hostAddress types.Address) types.V2FileContract { return types.V2FileContract{ @@ -626,23 +582,22 @@ func PayWithContract(fc *types.V2FileContract, amount, collateral types.Currency return nil } -// ReviseForModifySectors creates a contract revision from a modify sectors request +// ReviseForRemoveSectors creates a contract revision from a modify sectors request // and response. -func ReviseForModifySectors(fc types.V2FileContract, prices HostPrices, root types.Hash256, actions []ModifyAction) (types.V2FileContract, error) { - for _, action := range actions { - if action.Type == ActionTrim { - fc.Filesize -= SectorSize * action.N - } - } - if err := PayWithContract(&fc, prices.RPCModifySectorsCost(actions), types.ZeroCurrency); err != nil { +func ReviseForRemoveSectors(fc types.V2FileContract, prices HostPrices, newRoot types.Hash256, deletions int) (types.V2FileContract, error) { + fc.Filesize -= SectorSize * uint64(deletions) + if err := PayWithContract(&fc, prices.RPCRemoveSectorsCost(deletions), types.ZeroCurrency); err != nil { return fc, err } - fc.FileMerkleRoot = root + fc.FileMerkleRoot = newRoot return fc, nil } // ReviseForAppendSectors creates a contract revision from an append sectors request func ReviseForAppendSectors(fc types.V2FileContract, prices HostPrices, root types.Hash256, appended uint64) (types.V2FileContract, error) { + sectors := fc.Filesize / SectorSize + capacity := fc.Filesize / SectorSize // TODO: use Capacity field + appended -= capacity - sectors // capacity will always be >= sectors cost, collateral := prices.RPCAppendSectorsCost(appended, fc.ExpirationHeight-prices.TipHeight) if err := PayWithContract(&fc, cost, collateral); err != nil { return fc, err diff --git a/rhp/v4/validation.go b/rhp/v4/validation.go index 58aab0fd..4ed311b2 100644 --- a/rhp/v4/validation.go +++ b/rhp/v4/validation.go @@ -48,15 +48,17 @@ func (req *RPCWriteSectorStreamingRequest) Validate(pk types.PublicKey, maxDurat } // Validate validates a modify sectors request. Signatures are not validated. -func (req *RPCModifySectorsRequest) Validate(pk types.PublicKey, maxActions uint64) error { +func (req *RPCRemoveSectorsRequest) Validate(pk types.PublicKey, maxActions uint64) error { if err := req.Prices.Validate(pk); err != nil { return fmt.Errorf("prices are invalid: %w", err) + } else if uint64(len(req.Indices)) > maxActions { + return fmt.Errorf("removing to many sectors at once: %d > %d", len(req.Indices), maxActions) } - return ValidateModifyActions(req.Actions, maxActions) + return nil } // Validate validates a sector roots request. Signatures are not validated. -func (req *RPCSectorRootsRequest) Validate(pk types.PublicKey, fc types.V2FileContract) error { +func (req *RPCSectorRootsRequest) Validate(pk types.PublicKey, fc types.V2FileContract, maxSectors uint64) error { if err := req.Prices.Validate(pk); err != nil { return fmt.Errorf("prices are invalid: %w", err) } @@ -67,6 +69,8 @@ func (req *RPCSectorRootsRequest) Validate(pk types.PublicKey, fc types.V2FileCo return errors.New("length must be greater than 0") case req.Length+req.Offset > contractSectors: return fmt.Errorf("read request range exceeds contract sectors: %d > %d", req.Length+req.Offset, contractSectors) + case req.Length > maxSectors: + return fmt.Errorf("read request range exceeds maximum sectors: %d > %d", req.Length, maxSectors) } return nil } From cd694ed1f009fddbbe45d9b44befd5b695e61380 Mon Sep 17 00:00:00 2001 From: Nate Maninger Date: Mon, 21 Oct 2024 10:04:46 -0700 Subject: [PATCH 02/16] rhp4: update docstring --- rhp/v4/rhp.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/rhp/v4/rhp.go b/rhp/v4/rhp.go index f2e73410..7240056e 100644 --- a/rhp/v4/rhp.go +++ b/rhp/v4/rhp.go @@ -85,9 +85,7 @@ func (hp HostPrices) RPCVerifySectorCost() types.Currency { return hp.EgressPrice.Mul64(SectorSize) } -// RPCRemoveSectorsCost returns the cost of modifying a contract's sectors with the -// given actions. The duration parameter is the number of blocks until the -// contract's expiration height. +// RPCRemoveSectorsCost returns the cost of removing sectors from a contract. func (hp HostPrices) RPCRemoveSectorsCost(sectors int) (cost types.Currency) { return hp.RemoveSectorPrice.Mul64(uint64(sectors)) } From 7cabe01e475e2026db32f259110fd4e4ab6ff3d0 Mon Sep 17 00:00:00 2001 From: Nate Maninger Date: Mon, 21 Oct 2024 10:06:36 -0700 Subject: [PATCH 03/16] rhp4: fix lint --- rhp/v4/merkle.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rhp/v4/merkle.go b/rhp/v4/merkle.go index a171fedd..97201083 100644 --- a/rhp/v4/merkle.go +++ b/rhp/v4/merkle.go @@ -76,7 +76,7 @@ func BuildAppendProof(sectorRoots, appended []types.Hash256) ([]types.Hash256, t return subtreeRoots, acc.Root() } -// VerifyAppendProof verifies a Merkle proof produced by BuildAppendProof. +// VerifyAppendSectorsProof verifies a Merkle proof produced by BuildAppendProof. func VerifyAppendSectorsProof(numSectors uint64, subtreeRoots []types.Hash256, appended []types.Hash256, oldRoot, newRoot types.Hash256) bool { acc := blake2b.Accumulator{NumLeaves: numSectors} for i := 0; i < bits.Len64(numSectors); i++ { From aef0242f030711d343838d5f071a52c98cba7b45 Mon Sep 17 00:00:00 2001 From: lukechampine Date: Mon, 21 Oct 2024 14:16:57 -0400 Subject: [PATCH 04/16] types,consensus: Add Capacity field to V2FileContract --- consensus/update_test.go | 1 + consensus/validation.go | 6 ++++++ consensus/validation_test.go | 1 + types/encoding.go | 2 ++ types/types.go | 1 + 5 files changed, 11 insertions(+) diff --git a/consensus/update_test.go b/consensus/update_test.go index 097ad351..62aedac1 100644 --- a/consensus/update_test.go +++ b/consensus/update_test.go @@ -1084,6 +1084,7 @@ func TestApplyRevertBlockV2(t *testing.T) { v1FC.Filesize = 65 v1FC.FileMerkleRoot = blake2b.SumPair((State{}).StorageProofLeafHash([]byte{1}), (State{}).StorageProofLeafHash([]byte{2})) v2FC := types.V2FileContract{ + Capacity: v1FC.Filesize, Filesize: v1FC.Filesize, FileMerkleRoot: v1FC.FileMerkleRoot, ProofHeight: 20, diff --git a/consensus/validation.go b/consensus/validation.go index 60ac38bd..32bb1523 100644 --- a/consensus/validation.go +++ b/consensus/validation.go @@ -725,6 +725,8 @@ func validateV2FileContracts(ms *MidState, txn types.V2Transaction) error { validateContract := func(fc types.V2FileContract, renewal bool) error { switch { + case fc.Filesize > fc.Capacity: + return fmt.Errorf("has filesize (%v) exceeding capacity (%v)", fc.Filesize, fc.Capacity) case fc.ProofHeight < ms.base.childHeight(): return fmt.Errorf("has proof height (%v) that has already passed", fc.ProofHeight) case fc.ExpirationHeight <= fc.ProofHeight: @@ -747,6 +749,10 @@ func validateV2FileContracts(ms *MidState, txn types.V2Transaction) error { curOutputSum := cur.RenterOutput.Value.Add(cur.HostOutput.Value) revOutputSum := rev.RenterOutput.Value.Add(rev.HostOutput.Value) switch { + case rev.Capacity < cur.Capacity: + return fmt.Errorf("decreases capacity") + case rev.Filesize > rev.Capacity: + return fmt.Errorf("has filesize (%v) exceeding capacity (%v)", rev.Filesize, rev.Capacity) case cur.ProofHeight < ms.base.childHeight(): return fmt.Errorf("revises contract after its proof window has opened") case rev.RevisionNumber <= cur.RevisionNumber: diff --git a/consensus/validation_test.go b/consensus/validation_test.go index 223059c7..96185832 100644 --- a/consensus/validation_test.go +++ b/consensus/validation_test.go @@ -863,6 +863,7 @@ func TestValidateV2Block(t *testing.T) { v1GiftFC.Filesize = 65 v1GiftFC.FileMerkleRoot = blake2b.SumPair((State{}).StorageProofLeafHash([]byte{1}), (State{}).StorageProofLeafHash([]byte{2})) v2GiftFC := types.V2FileContract{ + Capacity: v1GiftFC.Filesize, Filesize: v1GiftFC.Filesize, FileMerkleRoot: v1GiftFC.FileMerkleRoot, ProofHeight: 20, diff --git a/types/encoding.go b/types/encoding.go index d1a8477c..2586abcf 100644 --- a/types/encoding.go +++ b/types/encoding.go @@ -651,6 +651,7 @@ func (sfe SiafundElement) EncodeTo(e *Encoder) { // EncodeTo implements types.EncoderTo. func (fc V2FileContract) EncodeTo(e *Encoder) { + e.WriteUint64(fc.Capacity) e.WriteUint64(fc.Filesize) fc.FileMerkleRoot.EncodeTo(e) e.WriteUint64(fc.ProofHeight) @@ -1246,6 +1247,7 @@ func (sfe *SiafundElement) DecodeFrom(d *Decoder) { // DecodeFrom implements types.DecoderFrom. func (fc *V2FileContract) DecodeFrom(d *Decoder) { + fc.Capacity = d.ReadUint64() fc.Filesize = d.ReadUint64() fc.FileMerkleRoot.DecodeFrom(d) fc.ProofHeight = d.ReadUint64() diff --git a/types/types.go b/types/types.go index 2b58f9e4..bdee4ed5 100644 --- a/types/types.go +++ b/types/types.go @@ -455,6 +455,7 @@ func (txn *Transaction) TotalFees() Currency { // or "missed" depending on whether a valid StorageProof is submitted for the // contract. type V2FileContract struct { + Capacity uint64 `json:"capacity"` Filesize uint64 `json:"filesize"` FileMerkleRoot Hash256 `json:"fileMerkleRoot"` ProofHeight uint64 `json:"proofHeight"` From bed2bdcfff69b58b617bf240ab79936abc74c0cb Mon Sep 17 00:00:00 2001 From: lukechampine Date: Mon, 21 Oct 2024 14:16:57 -0400 Subject: [PATCH 05/16] types,consensus: Add Capacity field to V2FileContract --- consensus/update_test.go | 1 + consensus/validation.go | 6 ++++++ consensus/validation_test.go | 1 + types/encoding.go | 2 ++ types/types.go | 1 + 5 files changed, 11 insertions(+) diff --git a/consensus/update_test.go b/consensus/update_test.go index 097ad351..62aedac1 100644 --- a/consensus/update_test.go +++ b/consensus/update_test.go @@ -1084,6 +1084,7 @@ func TestApplyRevertBlockV2(t *testing.T) { v1FC.Filesize = 65 v1FC.FileMerkleRoot = blake2b.SumPair((State{}).StorageProofLeafHash([]byte{1}), (State{}).StorageProofLeafHash([]byte{2})) v2FC := types.V2FileContract{ + Capacity: v1FC.Filesize, Filesize: v1FC.Filesize, FileMerkleRoot: v1FC.FileMerkleRoot, ProofHeight: 20, diff --git a/consensus/validation.go b/consensus/validation.go index 7a41ff95..fa939deb 100644 --- a/consensus/validation.go +++ b/consensus/validation.go @@ -715,6 +715,8 @@ func validateV2FileContracts(ms *MidState, txn types.V2Transaction) error { validateContract := func(fc types.V2FileContract, renewal bool) error { switch { + case fc.Filesize > fc.Capacity: + return fmt.Errorf("has filesize (%v) exceeding capacity (%v)", fc.Filesize, fc.Capacity) case fc.ProofHeight < ms.base.childHeight(): return fmt.Errorf("has proof height (%v) that has already passed", fc.ProofHeight) case fc.ExpirationHeight <= fc.ProofHeight: @@ -737,6 +739,10 @@ func validateV2FileContracts(ms *MidState, txn types.V2Transaction) error { curOutputSum := cur.RenterOutput.Value.Add(cur.HostOutput.Value) revOutputSum := rev.RenterOutput.Value.Add(rev.HostOutput.Value) switch { + case rev.Capacity < cur.Capacity: + return fmt.Errorf("decreases capacity") + case rev.Filesize > rev.Capacity: + return fmt.Errorf("has filesize (%v) exceeding capacity (%v)", rev.Filesize, rev.Capacity) case cur.ProofHeight < ms.base.childHeight(): return fmt.Errorf("revises contract after its proof window has opened") case rev.RevisionNumber <= cur.RevisionNumber: diff --git a/consensus/validation_test.go b/consensus/validation_test.go index dd13993d..96bf38c0 100644 --- a/consensus/validation_test.go +++ b/consensus/validation_test.go @@ -861,6 +861,7 @@ func TestValidateV2Block(t *testing.T) { v1GiftFC.Filesize = 65 v1GiftFC.FileMerkleRoot = blake2b.SumPair((State{}).StorageProofLeafHash([]byte{1}), (State{}).StorageProofLeafHash([]byte{2})) v2GiftFC := types.V2FileContract{ + Capacity: v1GiftFC.Filesize, Filesize: v1GiftFC.Filesize, FileMerkleRoot: v1GiftFC.FileMerkleRoot, ProofHeight: 20, diff --git a/types/encoding.go b/types/encoding.go index d1a8477c..2586abcf 100644 --- a/types/encoding.go +++ b/types/encoding.go @@ -651,6 +651,7 @@ func (sfe SiafundElement) EncodeTo(e *Encoder) { // EncodeTo implements types.EncoderTo. func (fc V2FileContract) EncodeTo(e *Encoder) { + e.WriteUint64(fc.Capacity) e.WriteUint64(fc.Filesize) fc.FileMerkleRoot.EncodeTo(e) e.WriteUint64(fc.ProofHeight) @@ -1246,6 +1247,7 @@ func (sfe *SiafundElement) DecodeFrom(d *Decoder) { // DecodeFrom implements types.DecoderFrom. func (fc *V2FileContract) DecodeFrom(d *Decoder) { + fc.Capacity = d.ReadUint64() fc.Filesize = d.ReadUint64() fc.FileMerkleRoot.DecodeFrom(d) fc.ProofHeight = d.ReadUint64() diff --git a/types/types.go b/types/types.go index 2b58f9e4..bdee4ed5 100644 --- a/types/types.go +++ b/types/types.go @@ -455,6 +455,7 @@ func (txn *Transaction) TotalFees() Currency { // or "missed" depending on whether a valid StorageProof is submitted for the // contract. type V2FileContract struct { + Capacity uint64 `json:"capacity"` Filesize uint64 `json:"filesize"` FileMerkleRoot Hash256 `json:"fileMerkleRoot"` ProofHeight uint64 `json:"proofHeight"` From f0d4bdac2ea3ce55f529469480c8fa1a87d3a906 Mon Sep 17 00:00:00 2001 From: Nate Maninger Date: Mon, 21 Oct 2024 12:49:38 -0700 Subject: [PATCH 06/16] rhp4: use capacity field --- rhp/v4/rhp.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rhp/v4/rhp.go b/rhp/v4/rhp.go index 7240056e..07152588 100644 --- a/rhp/v4/rhp.go +++ b/rhp/v4/rhp.go @@ -594,8 +594,8 @@ func ReviseForRemoveSectors(fc types.V2FileContract, prices HostPrices, newRoot // ReviseForAppendSectors creates a contract revision from an append sectors request func ReviseForAppendSectors(fc types.V2FileContract, prices HostPrices, root types.Hash256, appended uint64) (types.V2FileContract, error) { sectors := fc.Filesize / SectorSize - capacity := fc.Filesize / SectorSize // TODO: use Capacity field - appended -= capacity - sectors // capacity will always be >= sectors + capacity := fc.Capacity / SectorSize + appended -= capacity - sectors // capacity will always be >= sectors cost, collateral := prices.RPCAppendSectorsCost(appended, fc.ExpirationHeight-prices.TipHeight) if err := PayWithContract(&fc, cost, collateral); err != nil { return fc, err From fd212fd877d4a5cae5621ca763cc8bfccbd1ccb4 Mon Sep 17 00:00:00 2001 From: Nate Maninger Date: Mon, 21 Oct 2024 13:03:09 -0700 Subject: [PATCH 07/16] rhp4: validate sector indices --- rhp/v4/validation.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/rhp/v4/validation.go b/rhp/v4/validation.go index 4ed311b2..207af0fd 100644 --- a/rhp/v4/validation.go +++ b/rhp/v4/validation.go @@ -48,12 +48,18 @@ func (req *RPCWriteSectorStreamingRequest) Validate(pk types.PublicKey, maxDurat } // Validate validates a modify sectors request. Signatures are not validated. -func (req *RPCRemoveSectorsRequest) Validate(pk types.PublicKey, maxActions uint64) error { +func (req *RPCRemoveSectorsRequest) Validate(pk types.PublicKey, fc types.V2FileContract, maxActions uint64) error { if err := req.Prices.Validate(pk); err != nil { return fmt.Errorf("prices are invalid: %w", err) } else if uint64(len(req.Indices)) > maxActions { return fmt.Errorf("removing to many sectors at once: %d > %d", len(req.Indices), maxActions) } + sectors := fc.Filesize / SectorSize + for _, index := range req.Indices { + if index >= sectors { + return fmt.Errorf("sector index %d exceeds contract sectors %d", index, sectors) + } + } return nil } From dfdf69e37844c9dc5eb0750eb9a5b3d868bf4027 Mon Sep 17 00:00:00 2001 From: Nate Maninger Date: Mon, 21 Oct 2024 13:19:48 -0700 Subject: [PATCH 08/16] rhp4: validate duplicate indices --- rhp/v4/validation.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rhp/v4/validation.go b/rhp/v4/validation.go index 207af0fd..fc2029f0 100644 --- a/rhp/v4/validation.go +++ b/rhp/v4/validation.go @@ -54,11 +54,15 @@ func (req *RPCRemoveSectorsRequest) Validate(pk types.PublicKey, fc types.V2File } else if uint64(len(req.Indices)) > maxActions { return fmt.Errorf("removing to many sectors at once: %d > %d", len(req.Indices), maxActions) } + seen := make(map[uint64]bool) sectors := fc.Filesize / SectorSize for _, index := range req.Indices { if index >= sectors { return fmt.Errorf("sector index %d exceeds contract sectors %d", index, sectors) + } else if seen[index] { + return fmt.Errorf("duplicate sector index %d", index) } + seen[index] = true } return nil } From 8ee63c44147b1ab8b9a56d73588c5abc25ecdfd0 Mon Sep 17 00:00:00 2001 From: Nate Maninger Date: Mon, 21 Oct 2024 14:45:06 -0700 Subject: [PATCH 09/16] rhp4: return usage --- rhp/v4/rhp.go | 103 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 75 insertions(+), 28 deletions(-) diff --git a/rhp/v4/rhp.go b/rhp/v4/rhp.go index 07152588..240bbc95 100644 --- a/rhp/v4/rhp.go +++ b/rhp/v4/rhp.go @@ -39,6 +39,38 @@ func round4KiB(n uint64) uint64 { return (n + (1<<12 - 1)) &^ (1<<12 - 1) } +// Usage contains the cost breakdown and collateral of executing an RPC. +type Usage struct { + RPC types.Currency `json:"rpc"` + Storage types.Currency `json:"storage"` + Egress types.Currency `json:"egress"` + Ingress types.Currency `json:"ingress"` + AccountFunding types.Currency `json:"accountFunding"` + Collateral types.Currency `json:"collateral"` +} + +// Cost returns the total cost of executing the RPC. +func (u Usage) RenterCost() types.Currency { + return u.RPC.Add(u.Storage).Add(u.Egress).Add(u.Ingress).Add(u.AccountFunding) +} + +// HostCollateral returns the amount of collateral the host must risk +func (u Usage) HostCollateral() types.Currency { + return u.Collateral +} + +// Add returns the sum of two Usages. +func (u Usage) Add(b Usage) Usage { + return Usage{ + RPC: u.RPC.Add(b.RPC), + Storage: u.Storage.Add(b.Storage), + Egress: u.Egress.Add(b.Egress), + Ingress: u.Ingress.Add(b.Ingress), + AccountFunding: u.AccountFunding.Add(b.AccountFunding), + Collateral: u.Collateral.Add(b.Collateral), + } +} + // HostPrices specify a time-bound set of parameters used to calculate the cost // of various RPCs. type HostPrices struct { @@ -56,47 +88,62 @@ type HostPrices struct { } // RPCReadSectorCost returns the cost of reading a sector of the given length. -func (hp HostPrices) RPCReadSectorCost(length uint64) types.Currency { - return hp.EgressPrice.Mul64(round4KiB(length)) +func (hp HostPrices) RPCReadSectorCost(length uint64) Usage { + return Usage{ + Egress: hp.EgressPrice.Mul64(round4KiB(length)), + } } // RPCWriteSectorCost returns the cost of executing the WriteSector RPC with the // given sector length and duration. -func (hp HostPrices) RPCWriteSectorCost(sectorLength uint64, duration uint64) types.Currency { - storage, _ := hp.StoreSectorCost(duration) - return hp.IngressPrice.Mul64(round4KiB(sectorLength)).Add(storage) +func (hp HostPrices) RPCWriteSectorCost(sectorLength uint64, duration uint64) Usage { + return hp.StoreSectorCost(duration).Add(Usage{ + Ingress: hp.IngressPrice.Mul64(round4KiB(sectorLength)), + }) } // StoreSectorCost returns the cost of storing a sector for the given duration. -func (hp HostPrices) StoreSectorCost(duration uint64) (storage types.Currency, collateral types.Currency) { - storage = hp.StoragePrice.Mul64(SectorSize).Mul64(duration) - collateral = hp.Collateral.Mul64(SectorSize).Mul64(duration) - return +func (hp HostPrices) StoreSectorCost(duration uint64) Usage { + return Usage{ + Storage: hp.StoragePrice.Mul64(SectorSize).Mul64(duration), + Collateral: hp.Collateral.Mul64(SectorSize).Mul64(duration), + } } // RPCSectorRootsCost returns the cost of fetching sector roots for the given length. -func (hp HostPrices) RPCSectorRootsCost(length uint64) types.Currency { - return hp.EgressPrice.Mul64(round4KiB(32 * length)) +func (hp HostPrices) RPCSectorRootsCost(length uint64) Usage { + return Usage{ + Egress: hp.EgressPrice.Mul64(round4KiB(32 * length)), + } +} + +// RPCFundAccountsCost returns the cost of funding the given accounts. +func (hp HostPrices) RPCFundAccountsCost(deposit types.Currency) Usage { + return Usage{AccountFunding: deposit} } // RPCVerifySectorCost returns the cost of building a proof for the specified // sector. -func (hp HostPrices) RPCVerifySectorCost() types.Currency { - return hp.EgressPrice.Mul64(SectorSize) +func (hp HostPrices) RPCVerifySectorCost() Usage { + return Usage{ + Egress: hp.EgressPrice.Mul64(SectorSize), + } } // RPCRemoveSectorsCost returns the cost of removing sectors from a contract. -func (hp HostPrices) RPCRemoveSectorsCost(sectors int) (cost types.Currency) { - return hp.RemoveSectorPrice.Mul64(uint64(sectors)) +func (hp HostPrices) RPCRemoveSectorsCost(sectors int) Usage { + return Usage{ + RPC: hp.RemoveSectorPrice.Mul64(uint64(sectors)), + } } // RPCAppendSectorsCost returns the cost of appending sectors to a contract. The duration // parameter is the number of blocks until the contract's expiration height. -func (hp HostPrices) RPCAppendSectorsCost(sectors, duration uint64) (cost, collateral types.Currency) { - storage, collateral := hp.StoreSectorCost(duration) - storage = storage.Mul64(sectors) - collateral = collateral.Mul64(sectors) - return storage, collateral +func (hp HostPrices) RPCAppendSectorsCost(sectors, duration uint64) Usage { + usage := hp.StoreSectorCost(duration) + usage.Storage = usage.Storage.Mul64(sectors) + usage.Collateral = usage.Collateral.Mul64(sectors) + return usage } // SigHash returns the hash of the host settings used for signing. @@ -563,7 +610,8 @@ func RefreshCost(cs consensus.State, p HostPrices, r types.V2FileContractRenewal // PayWithContract modifies a contract to transfer the amount from the renter and // deduct collateral from the host. It returns an RPC error if the contract does not // have sufficient funds. -func PayWithContract(fc *types.V2FileContract, amount, collateral types.Currency) error { +func PayWithContract(fc *types.V2FileContract, usage Usage) error { + amount, collateral := usage.RenterCost(), usage.HostCollateral() // verify the contract can pay the amount before modifying if fc.RenterOutput.Value.Cmp(amount) < 0 { return NewRPCError(ErrorCodePayment, fmt.Sprintf("insufficient renter funds: %v < %v", fc.RenterOutput.Value, amount)) @@ -584,7 +632,7 @@ func PayWithContract(fc *types.V2FileContract, amount, collateral types.Currency // and response. func ReviseForRemoveSectors(fc types.V2FileContract, prices HostPrices, newRoot types.Hash256, deletions int) (types.V2FileContract, error) { fc.Filesize -= SectorSize * uint64(deletions) - if err := PayWithContract(&fc, prices.RPCRemoveSectorsCost(deletions), types.ZeroCurrency); err != nil { + if err := PayWithContract(&fc, prices.RPCRemoveSectorsCost(deletions)); err != nil { return fc, err } fc.FileMerkleRoot = newRoot @@ -596,8 +644,7 @@ func ReviseForAppendSectors(fc types.V2FileContract, prices HostPrices, root typ sectors := fc.Filesize / SectorSize capacity := fc.Capacity / SectorSize appended -= capacity - sectors // capacity will always be >= sectors - cost, collateral := prices.RPCAppendSectorsCost(appended, fc.ExpirationHeight-prices.TipHeight) - if err := PayWithContract(&fc, cost, collateral); err != nil { + if err := PayWithContract(&fc, prices.RPCAppendSectorsCost(appended, fc.ExpirationHeight-prices.TipHeight)); err != nil { return fc, err } fc.Filesize += SectorSize * appended @@ -607,13 +654,13 @@ func ReviseForAppendSectors(fc types.V2FileContract, prices HostPrices, root typ // ReviseForSectorRoots creates a contract revision from a sector roots request func ReviseForSectorRoots(fc types.V2FileContract, prices HostPrices, numRoots uint64) (types.V2FileContract, error) { - err := PayWithContract(&fc, prices.EgressPrice.Mul64(round4KiB(32*numRoots)), types.ZeroCurrency) + err := PayWithContract(&fc, prices.RPCSectorRootsCost(numRoots)) return fc, err } -// ReviseForFundAccount creates a contract revision from a fund account request. -func ReviseForFundAccount(fc types.V2FileContract, amount types.Currency) (types.V2FileContract, error) { - err := PayWithContract(&fc, amount, types.ZeroCurrency) +// ReviseForFundAccounts creates a contract revision from a fund account request. +func ReviseForFundAccounts(fc types.V2FileContract, prices HostPrices, amount types.Currency) (types.V2FileContract, error) { + err := PayWithContract(&fc, prices.RPCFundAccountsCost(amount)) return fc, err } From 094716d3a638fa6e73cad9c418309f67165290f6 Mon Sep 17 00:00:00 2001 From: Nate Maninger Date: Mon, 21 Oct 2024 14:50:42 -0700 Subject: [PATCH 10/16] rhp4: remove account funding cost --- rhp/v4/rhp.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/rhp/v4/rhp.go b/rhp/v4/rhp.go index 240bbc95..fd06f837 100644 --- a/rhp/v4/rhp.go +++ b/rhp/v4/rhp.go @@ -117,11 +117,6 @@ func (hp HostPrices) RPCSectorRootsCost(length uint64) Usage { } } -// RPCFundAccountsCost returns the cost of funding the given accounts. -func (hp HostPrices) RPCFundAccountsCost(deposit types.Currency) Usage { - return Usage{AccountFunding: deposit} -} - // RPCVerifySectorCost returns the cost of building a proof for the specified // sector. func (hp HostPrices) RPCVerifySectorCost() Usage { @@ -659,8 +654,8 @@ func ReviseForSectorRoots(fc types.V2FileContract, prices HostPrices, numRoots u } // ReviseForFundAccounts creates a contract revision from a fund account request. -func ReviseForFundAccounts(fc types.V2FileContract, prices HostPrices, amount types.Currency) (types.V2FileContract, error) { - err := PayWithContract(&fc, prices.RPCFundAccountsCost(amount)) +func ReviseForFundAccounts(fc types.V2FileContract, amount types.Currency) (types.V2FileContract, error) { + err := PayWithContract(&fc, Usage{AccountFunding: amount}) return fc, err } From 54b5123bf5694c13d2b1ddebbd387bd6ac803154 Mon Sep 17 00:00:00 2001 From: Nate Maninger Date: Mon, 21 Oct 2024 14:54:33 -0700 Subject: [PATCH 11/16] rhp4: add usage to revise methods --- rhp/v4/rhp.go | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/rhp/v4/rhp.go b/rhp/v4/rhp.go index fd06f837..494521b1 100644 --- a/rhp/v4/rhp.go +++ b/rhp/v4/rhp.go @@ -625,38 +625,42 @@ func PayWithContract(fc *types.V2FileContract, usage Usage) error { // ReviseForRemoveSectors creates a contract revision from a modify sectors request // and response. -func ReviseForRemoveSectors(fc types.V2FileContract, prices HostPrices, newRoot types.Hash256, deletions int) (types.V2FileContract, error) { +func ReviseForRemoveSectors(fc types.V2FileContract, prices HostPrices, newRoot types.Hash256, deletions int) (types.V2FileContract, Usage, error) { fc.Filesize -= SectorSize * uint64(deletions) - if err := PayWithContract(&fc, prices.RPCRemoveSectorsCost(deletions)); err != nil { - return fc, err + usage := prices.RPCRemoveSectorsCost(deletions) + if err := PayWithContract(&fc, usage); err != nil { + return fc, Usage{}, err } fc.FileMerkleRoot = newRoot - return fc, nil + return fc, usage, nil } // ReviseForAppendSectors creates a contract revision from an append sectors request -func ReviseForAppendSectors(fc types.V2FileContract, prices HostPrices, root types.Hash256, appended uint64) (types.V2FileContract, error) { +func ReviseForAppendSectors(fc types.V2FileContract, prices HostPrices, root types.Hash256, appended uint64) (types.V2FileContract, Usage, error) { sectors := fc.Filesize / SectorSize capacity := fc.Capacity / SectorSize appended -= capacity - sectors // capacity will always be >= sectors - if err := PayWithContract(&fc, prices.RPCAppendSectorsCost(appended, fc.ExpirationHeight-prices.TipHeight)); err != nil { - return fc, err + usage := prices.RPCAppendSectorsCost(appended, fc.ExpirationHeight-prices.TipHeight) + if err := PayWithContract(&fc, usage); err != nil { + return fc, Usage{}, err } fc.Filesize += SectorSize * appended fc.FileMerkleRoot = root - return fc, nil + return fc, usage, nil } // ReviseForSectorRoots creates a contract revision from a sector roots request -func ReviseForSectorRoots(fc types.V2FileContract, prices HostPrices, numRoots uint64) (types.V2FileContract, error) { - err := PayWithContract(&fc, prices.RPCSectorRootsCost(numRoots)) - return fc, err +func ReviseForSectorRoots(fc types.V2FileContract, prices HostPrices, numRoots uint64) (types.V2FileContract, Usage, error) { + usage := prices.RPCSectorRootsCost(numRoots) + err := PayWithContract(&fc, usage) + return fc, usage, err } // ReviseForFundAccounts creates a contract revision from a fund account request. -func ReviseForFundAccounts(fc types.V2FileContract, amount types.Currency) (types.V2FileContract, error) { - err := PayWithContract(&fc, Usage{AccountFunding: amount}) - return fc, err +func ReviseForFundAccounts(fc types.V2FileContract, amount types.Currency) (types.V2FileContract, Usage, error) { + usage := Usage{AccountFunding: amount} + err := PayWithContract(&fc, usage) + return fc, usage, err } // MinRenterAllowance returns the minimum allowance required to justify the given From db1d712112bce0e263130819aa8c4038bc436473 Mon Sep 17 00:00:00 2001 From: Nate Maninger Date: Mon, 21 Oct 2024 14:59:09 -0700 Subject: [PATCH 12/16] rhp4: add usage to renew and refresh --- rhp/v4/rhp.go | 57 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/rhp/v4/rhp.go b/rhp/v4/rhp.go index 494521b1..68045734 100644 --- a/rhp/v4/rhp.go +++ b/rhp/v4/rhp.go @@ -41,12 +41,12 @@ func round4KiB(n uint64) uint64 { // Usage contains the cost breakdown and collateral of executing an RPC. type Usage struct { - RPC types.Currency `json:"rpc"` - Storage types.Currency `json:"storage"` - Egress types.Currency `json:"egress"` - Ingress types.Currency `json:"ingress"` - AccountFunding types.Currency `json:"accountFunding"` - Collateral types.Currency `json:"collateral"` + RPC types.Currency `json:"rpc"` + Storage types.Currency `json:"storage"` + Egress types.Currency `json:"egress"` + Ingress types.Currency `json:"ingress"` + AccountFunding types.Currency `json:"accountFunding"` + RiskedCollateral types.Currency `json:"collateral"` } // Cost returns the total cost of executing the RPC. @@ -54,20 +54,20 @@ func (u Usage) RenterCost() types.Currency { return u.RPC.Add(u.Storage).Add(u.Egress).Add(u.Ingress).Add(u.AccountFunding) } -// HostCollateral returns the amount of collateral the host must risk -func (u Usage) HostCollateral() types.Currency { - return u.Collateral +// HostRiskedCollateral returns the amount of collateral the host must risk +func (u Usage) HostRiskedCollateral() types.Currency { + return u.RiskedCollateral } // Add returns the sum of two Usages. func (u Usage) Add(b Usage) Usage { return Usage{ - RPC: u.RPC.Add(b.RPC), - Storage: u.Storage.Add(b.Storage), - Egress: u.Egress.Add(b.Egress), - Ingress: u.Ingress.Add(b.Ingress), - AccountFunding: u.AccountFunding.Add(b.AccountFunding), - Collateral: u.Collateral.Add(b.Collateral), + RPC: u.RPC.Add(b.RPC), + Storage: u.Storage.Add(b.Storage), + Egress: u.Egress.Add(b.Egress), + Ingress: u.Ingress.Add(b.Ingress), + AccountFunding: u.AccountFunding.Add(b.AccountFunding), + RiskedCollateral: u.RiskedCollateral.Add(b.RiskedCollateral), } } @@ -105,8 +105,8 @@ func (hp HostPrices) RPCWriteSectorCost(sectorLength uint64, duration uint64) Us // StoreSectorCost returns the cost of storing a sector for the given duration. func (hp HostPrices) StoreSectorCost(duration uint64) Usage { return Usage{ - Storage: hp.StoragePrice.Mul64(SectorSize).Mul64(duration), - Collateral: hp.Collateral.Mul64(SectorSize).Mul64(duration), + Storage: hp.StoragePrice.Mul64(SectorSize).Mul64(duration), + RiskedCollateral: hp.Collateral.Mul64(SectorSize).Mul64(duration), } } @@ -137,7 +137,7 @@ func (hp HostPrices) RPCRemoveSectorsCost(sectors int) Usage { func (hp HostPrices) RPCAppendSectorsCost(sectors, duration uint64) Usage { usage := hp.StoreSectorCost(duration) usage.Storage = usage.Storage.Mul64(sectors) - usage.Collateral = usage.Collateral.Mul64(sectors) + usage.RiskedCollateral = usage.RiskedCollateral.Mul64(sectors) return usage } @@ -606,7 +606,7 @@ func RefreshCost(cs consensus.State, p HostPrices, r types.V2FileContractRenewal // deduct collateral from the host. It returns an RPC error if the contract does not // have sufficient funds. func PayWithContract(fc *types.V2FileContract, usage Usage) error { - amount, collateral := usage.RenterCost(), usage.HostCollateral() + amount, collateral := usage.RenterCost(), usage.HostRiskedCollateral() // verify the contract can pay the amount before modifying if fc.RenterOutput.Value.Cmp(amount) < 0 { return NewRPCError(ErrorCodePayment, fmt.Sprintf("insufficient renter funds: %v < %v", fc.RenterOutput.Value, amount)) @@ -671,7 +671,8 @@ func MinRenterAllowance(hp HostPrices, duration uint64, collateral types.Currenc } // RenewContract creates a contract renewal from an existing contract revision -func RenewContract(fc types.V2FileContract, prices HostPrices, rp RPCRenewContractParams) (renewal types.V2FileContractRenewal) { +func RenewContract(fc types.V2FileContract, prices HostPrices, rp RPCRenewContractParams) (types.V2FileContractRenewal, Usage) { + var renewal types.V2FileContractRenewal // clear the old contract renewal.FinalRevision = fc renewal.FinalRevision.RevisionNumber = types.MaxRevisionNumber @@ -727,11 +728,17 @@ func RenewContract(fc types.V2FileContract, prices HostPrices, rp RPCRenewContra } else { renewal.RenterRollover = fc.RenterOutput.Value } - return + return renewal, Usage{ + RPC: prices.ContractPrice, + Storage: renewal.NewContract.HostOutput.Value.Sub(renewal.NewContract.TotalCollateral).Sub(prices.ContractPrice), + RiskedCollateral: renewal.NewContract.TotalCollateral.Sub(renewal.NewContract.MissedHostValue), + } } // RefreshContract creates a new contract renewal from an existing contract revision -func RefreshContract(fc types.V2FileContract, prices HostPrices, rp RPCRefreshContractParams) (renewal types.V2FileContractRenewal) { +func RefreshContract(fc types.V2FileContract, prices HostPrices, rp RPCRefreshContractParams) (types.V2FileContractRenewal, Usage) { + var renewal types.V2FileContractRenewal + // clear the old contract renewal.FinalRevision = fc renewal.FinalRevision.RevisionNumber = types.MaxRevisionNumber @@ -752,5 +759,9 @@ func RefreshContract(fc types.V2FileContract, prices HostPrices, rp RPCRefreshCo // roll over everything from the existing contract renewal.HostRollover = fc.HostOutput.Value renewal.RenterRollover = fc.RenterOutput.Value - return + return renewal, Usage{ + RPC: prices.ContractPrice, + Storage: renewal.NewContract.HostOutput.Value.Sub(renewal.NewContract.TotalCollateral).Sub(prices.ContractPrice), + RiskedCollateral: renewal.NewContract.TotalCollateral.Sub(renewal.NewContract.MissedHostValue), + } } From 063922806c778565ca092eae9373d016b19a4d74 Mon Sep 17 00:00:00 2001 From: Nate Maninger Date: Mon, 21 Oct 2024 15:07:56 -0700 Subject: [PATCH 13/16] rhp4: add usage to new contract --- rhp/v4/rhp.go | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/rhp/v4/rhp.go b/rhp/v4/rhp.go index 68045734..cf2b094c 100644 --- a/rhp/v4/rhp.go +++ b/rhp/v4/rhp.go @@ -559,26 +559,28 @@ func (r *RPCRefreshContractRequest) ValidChallengeSignature(existing types.V2Fil } // NewContract creates a new file contract with the given settings. -func NewContract(p HostPrices, cp RPCFormContractParams, hostKey types.PublicKey, hostAddress types.Address) types.V2FileContract { +func NewContract(p HostPrices, cp RPCFormContractParams, hostKey types.PublicKey, hostAddress types.Address) (types.V2FileContract, Usage) { return types.V2FileContract{ - Filesize: 0, - FileMerkleRoot: types.Hash256{}, - ProofHeight: cp.ProofHeight, - ExpirationHeight: cp.ProofHeight + proofWindow, - RenterOutput: types.SiacoinOutput{ - Value: cp.Allowance, - Address: cp.RenterAddress, - }, - HostOutput: types.SiacoinOutput{ - Value: cp.Collateral.Add(p.ContractPrice), - Address: hostAddress, - }, - MissedHostValue: cp.Collateral, - TotalCollateral: cp.Collateral, - RenterPublicKey: cp.RenterPublicKey, - HostPublicKey: hostKey, - RevisionNumber: 0, - } + Filesize: 0, + FileMerkleRoot: types.Hash256{}, + ProofHeight: cp.ProofHeight, + ExpirationHeight: cp.ProofHeight + proofWindow, + RenterOutput: types.SiacoinOutput{ + Value: cp.Allowance, + Address: cp.RenterAddress, + }, + HostOutput: types.SiacoinOutput{ + Value: cp.Collateral.Add(p.ContractPrice), + Address: hostAddress, + }, + MissedHostValue: cp.Collateral, + TotalCollateral: cp.Collateral, + RenterPublicKey: cp.RenterPublicKey, + HostPublicKey: hostKey, + RevisionNumber: 0, + }, Usage{ + RPC: p.ContractPrice, + } } // ContractCost calculates the cost to the host and renter for forming a contract. From fe2567f2c58f14b611e61d369399ef5e00effdb1 Mon Sep 17 00:00:00 2001 From: Nate Maninger Date: Mon, 21 Oct 2024 15:09:53 -0700 Subject: [PATCH 14/16] rhp4: fix docstring --- rhp/v4/rhp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rhp/v4/rhp.go b/rhp/v4/rhp.go index cf2b094c..eaa5f3a8 100644 --- a/rhp/v4/rhp.go +++ b/rhp/v4/rhp.go @@ -49,7 +49,7 @@ type Usage struct { RiskedCollateral types.Currency `json:"collateral"` } -// Cost returns the total cost of executing the RPC. +// RenterCost returns the total cost of executing the RPC. func (u Usage) RenterCost() types.Currency { return u.RPC.Add(u.Storage).Add(u.Egress).Add(u.Ingress).Add(u.AccountFunding) } From 5672e6c4271fa5b4ea5e7ffd4f66bd22e8f0ec41 Mon Sep 17 00:00:00 2001 From: Nate Maninger Date: Tue, 22 Oct 2024 07:39:15 -0700 Subject: [PATCH 15/16] Update rhp/v4/validation.go Co-authored-by: Christopher Schinnerl --- rhp/v4/validation.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rhp/v4/validation.go b/rhp/v4/validation.go index fc2029f0..d354ec15 100644 --- a/rhp/v4/validation.go +++ b/rhp/v4/validation.go @@ -52,7 +52,7 @@ func (req *RPCRemoveSectorsRequest) Validate(pk types.PublicKey, fc types.V2File if err := req.Prices.Validate(pk); err != nil { return fmt.Errorf("prices are invalid: %w", err) } else if uint64(len(req.Indices)) > maxActions { - return fmt.Errorf("removing to many sectors at once: %d > %d", len(req.Indices), maxActions) + return fmt.Errorf("removing too many sectors at once: %d > %d", len(req.Indices), maxActions) } seen := make(map[uint64]bool) sectors := fc.Filesize / SectorSize From 2652ab2ba1cfe70c8276e77f58f043e6e1e400e4 Mon Sep 17 00:00:00 2001 From: Nate Maninger Date: Tue, 22 Oct 2024 08:53:56 -0700 Subject: [PATCH 16/16] rhp4: RPC remove -> RPC free --- rhp/v4/encoding.go | 28 +++++++++--------- rhp/v4/rhp.go | 68 ++++++++++++++++++++++---------------------- rhp/v4/validation.go | 2 +- 3 files changed, 49 insertions(+), 49 deletions(-) diff --git a/rhp/v4/encoding.go b/rhp/v4/encoding.go index efed35b5..71650515 100644 --- a/rhp/v4/encoding.go +++ b/rhp/v4/encoding.go @@ -25,7 +25,7 @@ func (hp HostPrices) EncodeTo(e *types.Encoder) { types.V2Currency(hp.StoragePrice).EncodeTo(e) types.V2Currency(hp.IngressPrice).EncodeTo(e) types.V2Currency(hp.EgressPrice).EncodeTo(e) - types.V2Currency(hp.RemoveSectorPrice).EncodeTo(e) + types.V2Currency(hp.FreeSectorPrice).EncodeTo(e) e.WriteUint64(hp.TipHeight) e.WriteTime(hp.ValidUntil) hp.Signature.EncodeTo(e) @@ -38,7 +38,7 @@ func (hp *HostPrices) DecodeFrom(d *types.Decoder) { (*types.V2Currency)(&hp.StoragePrice).DecodeFrom(d) (*types.V2Currency)(&hp.IngressPrice).DecodeFrom(d) (*types.V2Currency)(&hp.EgressPrice).DecodeFrom(d) - (*types.V2Currency)(&hp.RemoveSectorPrice).DecodeFrom(d) + (*types.V2Currency)(&hp.FreeSectorPrice).DecodeFrom(d) hp.TipHeight = d.ReadUint64() hp.ValidUntil = d.ReadTime() hp.Signature.DecodeFrom(d) @@ -354,7 +354,7 @@ func (r *RPCRefreshContractThirdResponse) maxLen() int { return reasonableObjectSize } -func (r *RPCRemoveSectorsRequest) encodeTo(e *types.Encoder) { +func (r *RPCFreeSectorsRequest) encodeTo(e *types.Encoder) { r.ContractID.EncodeTo(e) r.Prices.EncodeTo(e) types.EncodeSliceFn(e, r.Indices, func(e *types.Encoder, v uint64) { @@ -362,7 +362,7 @@ func (r *RPCRemoveSectorsRequest) encodeTo(e *types.Encoder) { }) r.ChallengeSignature.EncodeTo(e) } -func (r *RPCRemoveSectorsRequest) decodeFrom(d *types.Decoder) { +func (r *RPCFreeSectorsRequest) decodeFrom(d *types.Decoder) { r.ContractID.DecodeFrom(d) r.Prices.DecodeFrom(d) types.DecodeSliceFn(d, &r.Indices, func(d *types.Decoder) uint64 { @@ -370,41 +370,41 @@ func (r *RPCRemoveSectorsRequest) decodeFrom(d *types.Decoder) { }) r.ChallengeSignature.DecodeFrom(d) } -func (r *RPCRemoveSectorsRequest) maxLen() int { +func (r *RPCFreeSectorsRequest) maxLen() int { return reasonableObjectSize } -func (r *RPCRemoveSectorsResponse) encodeTo(e *types.Encoder) { +func (r *RPCFreeSectorsResponse) encodeTo(e *types.Encoder) { types.EncodeSlice(e, r.OldSubtreeHashes) types.EncodeSlice(e, r.OldLeafHashes) r.NewMerkleRoot.EncodeTo(e) } -func (r *RPCRemoveSectorsResponse) decodeFrom(d *types.Decoder) { +func (r *RPCFreeSectorsResponse) decodeFrom(d *types.Decoder) { types.DecodeSlice(d, &r.OldSubtreeHashes) types.DecodeSlice(d, &r.OldLeafHashes) r.NewMerkleRoot.DecodeFrom(d) } -func (r *RPCRemoveSectorsResponse) maxLen() int { +func (r *RPCFreeSectorsResponse) maxLen() int { return reasonableObjectSize } -func (r *RPCRemoveSectorsSecondResponse) encodeTo(e *types.Encoder) { +func (r *RPCFreeSectorsSecondResponse) encodeTo(e *types.Encoder) { r.RenterSignature.EncodeTo(e) } -func (r *RPCRemoveSectorsSecondResponse) decodeFrom(d *types.Decoder) { +func (r *RPCFreeSectorsSecondResponse) decodeFrom(d *types.Decoder) { r.RenterSignature.DecodeFrom(d) } -func (r *RPCRemoveSectorsSecondResponse) maxLen() int { +func (r *RPCFreeSectorsSecondResponse) maxLen() int { return sizeofSignature } -func (r *RPCRemoveSectorsThirdResponse) encodeTo(e *types.Encoder) { +func (r *RPCFreeSectorsThirdResponse) encodeTo(e *types.Encoder) { r.HostSignature.EncodeTo(e) } -func (r *RPCRemoveSectorsThirdResponse) decodeFrom(d *types.Decoder) { +func (r *RPCFreeSectorsThirdResponse) decodeFrom(d *types.Decoder) { r.HostSignature.DecodeFrom(d) } -func (r *RPCRemoveSectorsThirdResponse) maxLen() int { +func (r *RPCFreeSectorsThirdResponse) maxLen() int { return sizeofSignature } diff --git a/rhp/v4/rhp.go b/rhp/v4/rhp.go index eaa5f3a8..5bc2240a 100644 --- a/rhp/v4/rhp.go +++ b/rhp/v4/rhp.go @@ -25,7 +25,7 @@ var ( RPCFundAccountsID = types.NewSpecifier("FundAccounts") RPCLatestRevisionID = types.NewSpecifier("LatestRevision") RPCAppendSectorsID = types.NewSpecifier("AppendSectors") - RPCRemoveSectorsID = types.NewSpecifier("RemoveSectors") + RPCFreeSectorsID = types.NewSpecifier("FreeSectors") RPCReadSectorID = types.NewSpecifier("ReadSector") RPCRenewContractID = types.NewSpecifier("RenewContract") RPCRefreshContractID = types.NewSpecifier("RefreshContract") @@ -74,14 +74,14 @@ func (u Usage) Add(b Usage) Usage { // HostPrices specify a time-bound set of parameters used to calculate the cost // of various RPCs. type HostPrices struct { - ContractPrice types.Currency `json:"contractPrice"` - Collateral types.Currency `json:"collateral"` - StoragePrice types.Currency `json:"storagePrice"` - IngressPrice types.Currency `json:"ingressPrice"` - EgressPrice types.Currency `json:"egressPrice"` - RemoveSectorPrice types.Currency `json:"removeSectorPrice"` - TipHeight uint64 `json:"tipHeight"` - ValidUntil time.Time `json:"validUntil"` + ContractPrice types.Currency `json:"contractPrice"` + Collateral types.Currency `json:"collateral"` + StoragePrice types.Currency `json:"storagePrice"` + IngressPrice types.Currency `json:"ingressPrice"` + EgressPrice types.Currency `json:"egressPrice"` + FreeSectorPrice types.Currency `json:"freeSectorPrice"` + TipHeight uint64 `json:"tipHeight"` + ValidUntil time.Time `json:"validUntil"` // covers above fields Signature types.Signature `json:"signature"` @@ -125,10 +125,10 @@ func (hp HostPrices) RPCVerifySectorCost() Usage { } } -// RPCRemoveSectorsCost returns the cost of removing sectors from a contract. -func (hp HostPrices) RPCRemoveSectorsCost(sectors int) Usage { +// RPCFreeSectorsCost returns the cost of removing sectors from a contract. +func (hp HostPrices) RPCFreeSectorsCost(sectors int) Usage { return Usage{ - RPC: hp.RemoveSectorPrice.Mul64(uint64(sectors)), + RPC: hp.FreeSectorPrice.Mul64(uint64(sectors)), } } @@ -149,7 +149,7 @@ func (hp HostPrices) SigHash() types.Hash256 { types.V2Currency(hp.StoragePrice).EncodeTo(h.E) types.V2Currency(hp.IngressPrice).EncodeTo(h.E) types.V2Currency(hp.EgressPrice).EncodeTo(h.E) - types.V2Currency(hp.RemoveSectorPrice).EncodeTo(h.E) + types.V2Currency(hp.FreeSectorPrice).EncodeTo(h.E) h.E.WriteUint64(hp.TipHeight) h.E.WriteTime(hp.ValidUntil) return h.Sum() @@ -349,26 +349,26 @@ type ( TransactionSet []types.V2Transaction `json:"transactionSet"` } - // RPCRemoveSectorsRequest implements Object. - RPCRemoveSectorsRequest struct { + // RPCFreeSectorsRequest implements Object. + RPCFreeSectorsRequest struct { ContractID types.FileContractID `json:"contractID"` Prices HostPrices `json:"prices"` Indices []uint64 `json:"indices"` // A ChallengeSignature proves the renter can modify the contract. ChallengeSignature types.Signature `json:"challengeSignature"` } - // RPCRemoveSectorsResponse implements Object. - RPCRemoveSectorsResponse struct { + // RPCFreeSectorsResponse implements Object. + RPCFreeSectorsResponse struct { OldSubtreeHashes []types.Hash256 `json:"oldSubtreeHashes"` OldLeafHashes []types.Hash256 `json:"oldLeafHashes"` NewMerkleRoot types.Hash256 `json:"newMerkleRoot"` } - // RPCRemoveSectorsSecondResponse implements Object. - RPCRemoveSectorsSecondResponse struct { + // RPCFreeSectorsSecondResponse implements Object. + RPCFreeSectorsSecondResponse struct { RenterSignature types.Signature `json:"renterSignature"` } - // RPCRemoveSectorsThirdResponse implements Object. - RPCRemoveSectorsThirdResponse struct { + // RPCFreeSectorsThirdResponse implements Object. + RPCFreeSectorsThirdResponse struct { HostSignature types.Signature `json:"hostSignature"` } @@ -504,7 +504,7 @@ type ( // ChallengeSigHash returns the hash of the challenge signature used for // signing. -func (r *RPCRemoveSectorsRequest) ChallengeSigHash(revisionNumber uint64) types.Hash256 { +func (r *RPCFreeSectorsRequest) ChallengeSigHash(revisionNumber uint64) types.Hash256 { h := types.NewHasher() r.ContractID.EncodeTo(h.E) h.E.WriteUint64(revisionNumber) @@ -512,7 +512,7 @@ func (r *RPCRemoveSectorsRequest) ChallengeSigHash(revisionNumber uint64) types. } // ValidChallengeSignature checks the challenge signature for validity. -func (r *RPCRemoveSectorsRequest) ValidChallengeSignature(fc types.V2FileContract) bool { +func (r *RPCFreeSectorsRequest) ValidChallengeSignature(fc types.V2FileContract) bool { return fc.RenterPublicKey.VerifyHash(r.ChallengeSigHash(fc.RevisionNumber+1), r.ChallengeSignature) } @@ -625,11 +625,10 @@ func PayWithContract(fc *types.V2FileContract, usage Usage) error { return nil } -// ReviseForRemoveSectors creates a contract revision from a modify sectors request -// and response. -func ReviseForRemoveSectors(fc types.V2FileContract, prices HostPrices, newRoot types.Hash256, deletions int) (types.V2FileContract, Usage, error) { +// ReviseForFreeSectors creates a contract revision for the free sectors RPC +func ReviseForFreeSectors(fc types.V2FileContract, prices HostPrices, newRoot types.Hash256, deletions int) (types.V2FileContract, Usage, error) { fc.Filesize -= SectorSize * uint64(deletions) - usage := prices.RPCRemoveSectorsCost(deletions) + usage := prices.RPCFreeSectorsCost(deletions) if err := PayWithContract(&fc, usage); err != nil { return fc, Usage{}, err } @@ -637,7 +636,7 @@ func ReviseForRemoveSectors(fc types.V2FileContract, prices HostPrices, newRoot return fc, usage, nil } -// ReviseForAppendSectors creates a contract revision from an append sectors request +// ReviseForAppendSectors creates a contract revision for the append sectors RPC func ReviseForAppendSectors(fc types.V2FileContract, prices HostPrices, root types.Hash256, appended uint64) (types.V2FileContract, Usage, error) { sectors := fc.Filesize / SectorSize capacity := fc.Capacity / SectorSize @@ -651,14 +650,14 @@ func ReviseForAppendSectors(fc types.V2FileContract, prices HostPrices, root typ return fc, usage, nil } -// ReviseForSectorRoots creates a contract revision from a sector roots request +// ReviseForSectorRoots creates a contract revision for the sector roots RPC func ReviseForSectorRoots(fc types.V2FileContract, prices HostPrices, numRoots uint64) (types.V2FileContract, Usage, error) { usage := prices.RPCSectorRootsCost(numRoots) err := PayWithContract(&fc, usage) return fc, usage, err } -// ReviseForFundAccounts creates a contract revision from a fund account request. +// ReviseForFundAccounts creates a contract revision for the fund accounts RPC func ReviseForFundAccounts(fc types.V2FileContract, amount types.Currency) (types.V2FileContract, Usage, error) { usage := Usage{AccountFunding: amount} err := PayWithContract(&fc, usage) @@ -672,7 +671,7 @@ func MinRenterAllowance(hp HostPrices, duration uint64, collateral types.Currenc return hp.StoragePrice.Mul64(duration).Mul(maxCollateralBytes) } -// RenewContract creates a contract renewal from an existing contract revision +// RenewContract creates a contract renewal for the renew RPC func RenewContract(fc types.V2FileContract, prices HostPrices, rp RPCRenewContractParams) (types.V2FileContractRenewal, Usage) { var renewal types.V2FileContractRenewal // clear the old contract @@ -704,8 +703,9 @@ func RenewContract(fc types.V2FileContract, prices HostPrices, rp RPCRenewContra // missed host value should only include the new collateral value renewal.NewContract.MissedHostValue = rp.Collateral - // storage cost is the difference between the new and old contract since the old contract - // already paid for the storage up to the current expiration height. + // storage cost is the difference between the new and old contract since the + // old contract already paid for the storage up to the current expiration + // height. storageCost := prices.StoragePrice.Mul64(fc.Filesize).Mul64(renewal.NewContract.ExpirationHeight - fc.ExpirationHeight) // host output value includes the locked + risked collateral, the additional @@ -737,7 +737,7 @@ func RenewContract(fc types.V2FileContract, prices HostPrices, rp RPCRenewContra } } -// RefreshContract creates a new contract renewal from an existing contract revision +// RefreshContract creates a contract renewal for the refresh RPC. func RefreshContract(fc types.V2FileContract, prices HostPrices, rp RPCRefreshContractParams) (types.V2FileContractRenewal, Usage) { var renewal types.V2FileContractRenewal diff --git a/rhp/v4/validation.go b/rhp/v4/validation.go index d354ec15..41fcfcbd 100644 --- a/rhp/v4/validation.go +++ b/rhp/v4/validation.go @@ -48,7 +48,7 @@ func (req *RPCWriteSectorStreamingRequest) Validate(pk types.PublicKey, maxDurat } // Validate validates a modify sectors request. Signatures are not validated. -func (req *RPCRemoveSectorsRequest) Validate(pk types.PublicKey, fc types.V2FileContract, maxActions uint64) error { +func (req *RPCFreeSectorsRequest) Validate(pk types.PublicKey, fc types.V2FileContract, maxActions uint64) error { if err := req.Prices.Validate(pk); err != nil { return fmt.Errorf("prices are invalid: %w", err) } else if uint64(len(req.Indices)) > maxActions {