Skip to content

Commit

Permalink
rhp4: add rpc replenish types
Browse files Browse the repository at this point in the history
  • Loading branch information
n8maninger committed Feb 14, 2025
1 parent 261f960 commit 5e7078f
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 10 deletions.
7 changes: 7 additions & 0 deletions .changeset/add_rpcreplenish_to_rhp4.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
default: minor
---

# Add RPCReplenish to RHP4

Adds an RPC to RHP4 that enables renters to set a target balance instead of first fetching the current balance and then funding the account with the difference. This is primarily to speed up account funding and reduce round trips when managing a large number of accounts.
46 changes: 46 additions & 0 deletions rhp/v4/encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,52 @@ func (r *RPCAccountBalanceResponse) maxLen() int {
return sizeofCurrency
}

func (r *RPCReplenishAccountsRequest) encodeTo(e *types.Encoder) {
types.EncodeSlice(e, r.Accounts)
types.V2Currency(r.Target).EncodeTo(e)
r.ContractID.EncodeTo(e)
r.ChallengeSignature.EncodeTo(e)
}
func (r *RPCReplenishAccountsRequest) decodeFrom(d *types.Decoder) {
types.DecodeSlice(d, &r.Accounts)
(*types.V2Currency)(&r.Target).DecodeFrom(d)
r.ContractID.DecodeFrom(d)
r.ChallengeSignature.DecodeFrom(d)
}
func (r *RPCReplenishAccountsRequest) maxLen() int {
return reasonableObjectSize
}

func (r *RPCReplenishAccountsResponse) encodeTo(e *types.Encoder) {
types.V2Currency(r.Cost).EncodeTo(e)
}
func (r *RPCReplenishAccountsResponse) decodeFrom(d *types.Decoder) {
(*types.V2Currency)(&r.Cost).DecodeFrom(d)
}
func (r *RPCReplenishAccountsResponse) maxLen() int {
return sizeofCurrency
}

func (r *RPCReplenishAccountsSecondResponse) encodeTo(e *types.Encoder) {
r.RenterSignature.EncodeTo(e)
}
func (r *RPCReplenishAccountsSecondResponse) decodeFrom(d *types.Decoder) {
r.RenterSignature.DecodeFrom(d)
}
func (r *RPCReplenishAccountsSecondResponse) maxLen() int {
return sizeofSignature
}

func (r *RPCReplenishAccountsThirdResponse) encodeTo(e *types.Encoder) {
r.HostSignature.EncodeTo(e)
}
func (r *RPCReplenishAccountsThirdResponse) decodeFrom(d *types.Decoder) {
r.HostSignature.DecodeFrom(d)
}
func (r *RPCReplenishAccountsThirdResponse) maxLen() int {
return sizeofSignature
}

func (r *RPCFundAccountsRequest) encodeTo(e *types.Encoder) {
r.ContractID.EncodeTo(e)
types.EncodeSlice(e, r.Deposits)
Expand Down
67 changes: 57 additions & 10 deletions rhp/v4/rhp.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,23 @@ const (

// RPC identifiers.
var (
RPCAccountBalanceID = types.NewSpecifier("AccountBalance")
RPCAccountBalanceID = types.NewSpecifier("AccountBalance")
RPCFundAccountsID = types.NewSpecifier("FundAccounts")
RPCReplenishAccountsID = types.NewSpecifier("ReplAccounts")

RPCAppendSectorsID = types.NewSpecifier("AppendSectors")
RPCFreeSectorsID = types.NewSpecifier("FreeSectors")
RPCSectorRootsID = types.NewSpecifier("SectorRoots")

RPCFormContractID = types.NewSpecifier("FormContract")
RPCFundAccountsID = types.NewSpecifier("FundAccounts")
RPCLatestRevisionID = types.NewSpecifier("LatestRevision")
RPCAppendSectorsID = types.NewSpecifier("AppendSectors")
RPCFreeSectorsID = types.NewSpecifier("FreeSectors")
RPCReadSectorID = types.NewSpecifier("ReadSector")
RPCRenewContractID = types.NewSpecifier("RenewContract")
RPCRefreshContractID = types.NewSpecifier("RefreshContract")
RPCSectorRootsID = types.NewSpecifier("SectorRoots")
RPCSettingsID = types.NewSpecifier("Settings")
RPCWriteSectorID = types.NewSpecifier("WriteSector")
RPCVerifySectorID = types.NewSpecifier("VerifySector")
RPCRenewContractID = types.NewSpecifier("RenewContract")

RPCReadSectorID = types.NewSpecifier("ReadSector")
RPCWriteSectorID = types.NewSpecifier("WriteSector")
RPCVerifySectorID = types.NewSpecifier("VerifySector")
RPCSettingsID = types.NewSpecifier("Settings")
)

func round4KiB(n uint64) uint64 {
Expand Down Expand Up @@ -458,6 +462,26 @@ type (
Balance types.Currency `json:"balance"`
}

// RPCReplenishAccountsRequest is the request type for RPCReplenishAccounts.
RPCReplenishAccountsRequest struct {
Accounts []Account `json:"accounts"`
Target types.Currency `json:"target"`
ContractID types.FileContractID `json:"contractID"`
ChallengeSignature types.Signature `json:"challengeSignature"`
}
// RPCReplenishAccountsResponse is the response type for RPCReplenishAccounts.
RPCReplenishAccountsResponse struct {
Cost types.Currency `json:"cost"`
}
// RPCReplenishAccountsSecondResponse is the second response type for RPCReplenishAccounts.
RPCReplenishAccountsSecondResponse struct {
RenterSignature types.Signature `json:"renterSignature"`
}
// RPCReplenishAccountsThirdResponse is the third response type for RPCReplenishAccounts.
RPCReplenishAccountsThirdResponse struct {
HostSignature types.Signature `json:"hostSignature"`
}

// RPCVerifySectorRequest implements Object.
RPCVerifySectorRequest struct {
Prices HostPrices `json:"prices"`
Expand Down Expand Up @@ -547,6 +571,22 @@ func (r *RPCRefreshContractRequest) ValidChallengeSignature(existing types.V2Fil
return existing.RenterPublicKey.VerifyHash(r.ChallengeSigHash(existing.RevisionNumber), r.ChallengeSignature)
}

// ChallengeSigHash returns the hash of the challenge signature used for
// signing.
func (r *RPCReplenishAccountsRequest) ChallengeSigHash(revisionNumber uint64) types.Hash256 {
h := types.NewHasher()
types.EncodeSlice(h.E, r.Accounts)
types.V2Currency(r.Target).EncodeTo(h.E)
r.ContractID.EncodeTo(h.E)
h.E.WriteUint64(revisionNumber)
return h.Sum()
}

// ValidChallengeSignature checks the challenge signature for validity.
func (r *RPCReplenishAccountsRequest) ValidChallengeSignature(fc types.V2FileContract) bool {
return fc.RenterPublicKey.VerifyHash(r.ChallengeSigHash(fc.RevisionNumber), r.ChallengeSignature)
}

// NewContract creates a new file contract with the given settings.
func NewContract(p HostPrices, cp RPCFormContractParams, hostKey types.PublicKey, hostAddress types.Address) (types.V2FileContract, Usage) {
return types.V2FileContract{
Expand Down Expand Up @@ -656,6 +696,13 @@ func ReviseForFundAccounts(fc types.V2FileContract, amount types.Currency) (type
return fc, usage, err
}

// ReviseForReplenish creates a contract revision for the replenish accounts RPC
func ReviseForReplenish(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
// host collateral.
func MinRenterAllowance(hp HostPrices, duration uint64, collateral types.Currency) types.Currency {
Expand Down
13 changes: 13 additions & 0 deletions rhp/v4/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,3 +249,16 @@ func (req *RPCAppendSectorsRequest) Validate(pk types.PublicKey) error {
}
return nil
}

// Validate checks that the request is valid
func (req *RPCReplenishAccountsRequest) Validate() error {
switch {
case len(req.Accounts) == 0:
return errors.New("no accounts to replenish")
case len(req.Accounts) > 100:
return fmt.Errorf("too many accounts to replenish: %d > %d", len(req.Accounts), 1000)
case req.Target.IsZero():
return errors.New("target must be greater than zero")
}
return nil
}

0 comments on commit 5e7078f

Please sign in to comment.