Skip to content

Commit

Permalink
rhp4: add common request validation methods
Browse files Browse the repository at this point in the history
  • Loading branch information
n8maninger committed Sep 17, 2024
1 parent a9e3f56 commit 057286a
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 47 deletions.
47 changes: 0 additions & 47 deletions rhp/v4/rhp.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package rhp
import (
"bytes"
"encoding/hex"
"errors"
"fmt"
"io"
"time"
Expand Down Expand Up @@ -549,52 +548,6 @@ func MinRenterAllowance(hp HostPrices, duration uint64, collateral types.Currenc
return hp.StoragePrice.Mul64(duration).Mul(maxCollateralBytes).Mul64(9).Div64(10) // 10% buffer
}

// ValidateFormContractParams checks the given contract parameters for validity.
func ValidateFormContractParams(hs HostSettings, tip types.ChainIndex, req RPCFormContractParams) error {
hp := hs.Prices
expirationHeight := req.ProofHeight + proofWindow
duration := expirationHeight - hp.TipHeight
minRenterAllowance := MinRenterAllowance(hp, duration, req.Collateral)

switch {
case expirationHeight <= hp.TipHeight: // must be validated against tip instead of prices
return errors.New("contract expiration height is in the past")
case req.Allowance.IsZero():
return errors.New("allowance is zero")
case req.Collateral.Cmp(hs.MaxCollateral) > 0:
return fmt.Errorf("collateral %v exceeds max collateral %v", req.Collateral, hs.MaxCollateral)
case duration > hs.MaxContractDuration:
return fmt.Errorf("contract duration %v exceeds max duration %v", duration, hs.MaxContractDuration)
case req.Allowance.Cmp(minRenterAllowance) < 0:
return fmt.Errorf("allowance %v is less than minimum %v for collateral", req.Allowance, minRenterAllowance)
default:
return nil
}
}

// ValidateRenewContractParams checks the given renew parameters for validity.
func ValidateRenewContractParams(hs HostSettings, tip types.ChainIndex, req RPCRenewContractParams) error {
hp := hs.Prices
expirationHeight := req.ProofHeight + proofWindow
duration := expirationHeight - hp.TipHeight
minRenterAllowance := MinRenterAllowance(hp, duration, req.Collateral)

switch {
case expirationHeight <= tip.Height: // must be validated against tip instead of prices
return errors.New("contract expiration height is in the past")
case req.Allowance.IsZero():
return errors.New("allowance is zero")
case req.Collateral.Cmp(hs.MaxCollateral) > 0:
return fmt.Errorf("collateral %v exceeds max collateral %v", req.Collateral, hs.MaxCollateral)
case duration > hs.MaxContractDuration:
return fmt.Errorf("contract duration %v exceeds max duration %v", duration, hs.MaxContractDuration)
case req.Allowance.Cmp(minRenterAllowance) < 0:
return fmt.Errorf("allowance %v is less than minimum %v for collateral", req.Allowance, minRenterAllowance)
default:
return nil
}
}

// NewRenewal creates a contract renewal from an existing contract revision
func NewRenewal(fc types.V2FileContract, prices HostPrices, rp RPCRenewContractParams) (renewal types.V2FileContractRenewal) {
expirationHeight := rp.ProofHeight + proofWindow
Expand Down
119 changes: 119 additions & 0 deletions rhp/v4/validation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package rhp

import (
"errors"
"fmt"

"go.sia.tech/core/types"
)

// Validate validates a read sector request.
func (req *RPCReadSectorRequest) Validate() error {
switch {
case req.Length == 0:
return errors.New("length must be greater than 0")
case req.Offset+req.Length > SectorSize:
return errors.New("read request exceeds sector bounds")
case (req.Offset+req.Length)%LeafSize != 0:
return errors.New("read request must be segment aligned")
}
return nil
}

// Validate validates a write sector request.
func (req *RPCWriteSectorRequest) Validate() error {
switch {
case req.Duration == 0:
return errors.New("duration must be greater than 0")
case len(req.Sector) == 0:
return errors.New("sector must not be empty")
case len(req.Sector)%LeafSize != 0:
return errors.New("sector must be segment aligned")
}
return nil
}

// Validate validates a sector roots request. Signatures are not validated.
func (req *RPCSectorRootsRequest) Validate(fc types.V2FileContract) error {
contractSectors := fc.Filesize / SectorSize

switch {
case req.Length == 0:
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)
}
return nil
}

// Validate validates a form contract request. Prices are not validated
func (req *RPCFormContractRequest) Validate(hs HostSettings, tip types.ChainIndex) error {
// validate the request fields
switch {
case req.MinerFee.IsZero():
return errors.New("miner fee must be greater than 0")
case req.Basis != (types.ChainIndex{}):
return errors.New("basis must be set")
case len(req.RenterInputs) == 0:
return errors.New("renter inputs must not be empty")
}

// validate the contract fields
hp := hs.Prices
expirationHeight := req.Contract.ProofHeight + proofWindow
duration := expirationHeight - hp.TipHeight
// calculate the minimum allowance required for the contract based on the
// host's locked collateral and the contract duration
minRenterAllowance := MinRenterAllowance(hp, duration, req.Contract.Collateral)

switch {
case expirationHeight <= tip.Height: // must be validated against tip instead of prices
return errors.New("contract expiration height is in the past")
case req.Contract.Allowance.IsZero():
return errors.New("allowance is zero")
case req.Contract.Collateral.Cmp(hs.MaxCollateral) > 0:
return fmt.Errorf("collateral %v exceeds max collateral %v", req.Contract.Collateral, hs.MaxCollateral)
case duration > hs.MaxContractDuration:
return fmt.Errorf("contract duration %v exceeds max duration %v", duration, hs.MaxContractDuration)
case req.Contract.Allowance.Cmp(minRenterAllowance) < 0:
return fmt.Errorf("allowance %v is less than minimum %v for collateral", req.Contract.Allowance, minRenterAllowance)
default:
return nil
}
}

// Validate validates a renew contract request. Prices are not validated
func (req *RPCRenewContractRequest) Validate(hs HostSettings, tip types.ChainIndex) error {
// validate the request fields
switch {
case req.MinerFee.IsZero():
return errors.New("miner fee must be greater than 0")
case req.Basis != (types.ChainIndex{}):
return errors.New("basis must be set")
case len(req.RenterInputs) == 0:
return errors.New("renter inputs must not be empty")
}

// validate the contract fields
hp := hs.Prices
expirationHeight := req.Renewal.ProofHeight + proofWindow
duration := expirationHeight - hp.TipHeight
// calculate the minimum allowance required for the contract based on the
// host's locked collateral and the contract duration
minRenterAllowance := MinRenterAllowance(hp, duration, req.Renewal.Collateral)

switch {
case expirationHeight <= tip.Height: // must be validated against tip instead of prices
return errors.New("contract expiration height is in the past")
case req.Renewal.Allowance.IsZero():
return errors.New("allowance is zero")
case req.Renewal.Collateral.Cmp(hs.MaxCollateral) > 0:
return fmt.Errorf("collateral %v exceeds max collateral %v", req.Renewal.Collateral, hs.MaxCollateral)
case duration > hs.MaxContractDuration:
return fmt.Errorf("contract duration %v exceeds max duration %v", duration, hs.MaxContractDuration)
case req.Renewal.Allowance.Cmp(minRenterAllowance) < 0:
return fmt.Errorf("allowance %v is less than minimum %v for collateral", req.Renewal.Allowance, minRenterAllowance)
default:
return nil
}
}

0 comments on commit 057286a

Please sign in to comment.