Skip to content

Commit

Permalink
rhp4: implement rpc changes
Browse files Browse the repository at this point in the history
  • Loading branch information
n8maninger committed Oct 21, 2024
1 parent efc26ef commit f72797b
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 134 deletions.
75 changes: 22 additions & 53 deletions rhp/v4/encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package rhp

import (
"bytes"
"fmt"

"go.sia.tech/core/types"
)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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[:]) }

Expand Down Expand Up @@ -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
}

Expand Down
3 changes: 3 additions & 0 deletions rhp/v4/merkle.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
}
*/
111 changes: 33 additions & 78 deletions rhp/v4/rhp.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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"`
Expand Down Expand Up @@ -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
Expand All @@ -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()
Expand All @@ -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
Expand Down Expand Up @@ -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"`
}

Expand Down Expand Up @@ -488,15 +464,15 @@ 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)
return h.Sum()
}

// 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)
}

Expand Down Expand Up @@ -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{
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit f72797b

Please sign in to comment.