Skip to content

Commit

Permalink
Add contract renewal endpoint to bus (#1475)
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisSchinnerl authored Aug 29, 2024
2 parents fc6e786 + f9b9226 commit 2ab36bb
Show file tree
Hide file tree
Showing 18 changed files with 249 additions and 342 deletions.
10 changes: 10 additions & 0 deletions api/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,16 @@ type (
LockID uint64 `json:"lockID"`
}

// ContractRenewRequest is the request type for the /contract/:id/renew
// endpoint.
ContractRenewRequest struct {
EndHeight uint64 `json:"endHeight"`
ExpectedNewStorage uint64 `json:"expectedNewStorage"`
MaxFundAmount types.Currency `json:"maxFundAmount"`
MinNewCollateral types.Currency `json:"minNewCollateral"`
RenterFunds types.Currency `json:"renterFunds"`
}

// ContractRenewedRequest is the request type for the /contract/:id/renewed
// endpoint.
ContractRenewedRequest struct {
Expand Down
25 changes: 0 additions & 25 deletions api/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"net/url"
"time"

rhpv3 "go.sia.tech/core/rhp/v3"
"go.sia.tech/core/types"
)

Expand Down Expand Up @@ -44,30 +43,6 @@ type (
DependsOn []types.Transaction `json:"dependsOn"`
}

// WalletPrepareRenewRequest is the request type for the /wallet/prepare/renew
// endpoint.
WalletPrepareRenewRequest struct {
Revision types.FileContractRevision `json:"revision"`
EndHeight uint64 `json:"endHeight"`
ExpectedNewStorage uint64 `json:"expectedNewStorage"`
HostAddress types.Address `json:"hostAddress"`
PriceTable rhpv3.HostPriceTable `json:"priceTable"`
MaxFundAmount types.Currency `json:"maxFundAmount"`
MinNewCollateral types.Currency `json:"minNewCollateral"`
RenterAddress types.Address `json:"renterAddress"`
RenterFunds types.Currency `json:"renterFunds"`
RenterKey types.PrivateKey `json:"renterKey"`
WindowSize uint64 `json:"windowSize"`
}

// WalletPrepareRenewResponse is the response type for the /wallet/prepare/renew
// endpoint.
WalletPrepareRenewResponse struct {
FundAmount types.Currency `json:"fundAmount"`
ToSign []types.Hash256 `json:"toSign"`
TransactionSet []types.Transaction `json:"transactionSet"`
}

// WalletRedistributeRequest is the request type for the /wallet/redistribute
// endpoint.
WalletRedistributeRequest struct {
Expand Down
25 changes: 0 additions & 25 deletions api/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,31 +108,6 @@ type (
Timeout DurationMS `json:"timeout"`
}

// RHPRenewRequest is the request type for the /rhp/renew endpoint.
RHPRenewRequest struct {
ContractID types.FileContractID `json:"contractID"`
EndHeight uint64 `json:"endHeight"`
ExpectedNewStorage uint64 `json:"expectedNewStorage"`
HostAddress types.Address `json:"hostAddress"`
HostKey types.PublicKey `json:"hostKey"`
MaxFundAmount types.Currency `json:"maxFundAmount"`
MinNewCollateral types.Currency `json:"minNewCollateral"`
SiamuxAddr string `json:"siamuxAddr"`
RenterAddress types.Address `json:"renterAddress"`
RenterFunds types.Currency `json:"renterFunds"`
WindowSize uint64 `json:"windowSize"`
}

// RHPRenewResponse is the response type for the /rhp/renew endpoint.
RHPRenewResponse struct {
Error string `json:"error"`
ContractID types.FileContractID `json:"contractID"`
Contract rhpv2.ContractRevision `json:"contract"`
ContractPrice types.Currency `json:"contractPrice"`
FundAmount types.Currency `json:"fundAmount"`
TransactionSet []types.Transaction `json:"transactionSet"`
}

// RHPScanRequest is the request type for the /rhp/scan endpoint.
RHPScanRequest struct {
HostKey types.PublicKey `json:"hostKey"`
Expand Down
3 changes: 1 addition & 2 deletions autopilot/autopilot.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"sync"
"time"

rhpv2 "go.sia.tech/core/rhp/v2"
"go.sia.tech/core/types"
"go.sia.tech/jape"
"go.sia.tech/renterd/alerts"
Expand Down Expand Up @@ -40,13 +39,13 @@ type Bus interface {
ConsensusState(ctx context.Context) (api.ConsensusState, error)

// contracts
AddRenewedContract(ctx context.Context, c rhpv2.ContractRevision, contractPrice, totalCost types.Currency, startHeight uint64, renewedFrom types.FileContractID, state string) (api.ContractMetadata, error)
AncestorContracts(ctx context.Context, id types.FileContractID, minStartHeight uint64) ([]api.ArchivedContract, error)
ArchiveContracts(ctx context.Context, toArchive map[types.FileContractID]string) error
Contract(ctx context.Context, id types.FileContractID) (api.ContractMetadata, error)
Contracts(ctx context.Context, opts api.ContractsOpts) (contracts []api.ContractMetadata, err error)
FileContractTax(ctx context.Context, payout types.Currency) (types.Currency, error)
FormContract(ctx context.Context, renterAddress types.Address, renterFunds types.Currency, hostKey types.PublicKey, hostIP string, hostCollateral types.Currency, endHeight uint64) (api.ContractMetadata, error)
RenewContract(ctx context.Context, fcid types.FileContractID, endHeight uint64, renterFunds, minNewCollateral, maxFundAmount types.Currency, expectedNewStorage uint64) (api.ContractMetadata, error)
SetContractSet(ctx context.Context, set string, contracts []types.FileContractID) error
PrunableData(ctx context.Context) (prunableData api.ContractsPrunableDataResponse, err error)

Expand Down
43 changes: 11 additions & 32 deletions autopilot/contractor/contractor.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,14 @@ const (
)

type Bus interface {
AddRenewedContract(ctx context.Context, c rhpv2.ContractRevision, contractPrice, totalCost types.Currency, startHeight uint64, renewedFrom types.FileContractID, state string) (api.ContractMetadata, error)
AncestorContracts(ctx context.Context, id types.FileContractID, minStartHeight uint64) ([]api.ArchivedContract, error)
ArchiveContracts(ctx context.Context, toArchive map[types.FileContractID]string) error
ConsensusState(ctx context.Context) (api.ConsensusState, error)
Contract(ctx context.Context, id types.FileContractID) (api.ContractMetadata, error)
Contracts(ctx context.Context, opts api.ContractsOpts) (contracts []api.ContractMetadata, err error)
FileContractTax(ctx context.Context, payout types.Currency) (types.Currency, error)
FormContract(ctx context.Context, renterAddress types.Address, renterFunds types.Currency, hostKey types.PublicKey, hostIP string, hostCollateral types.Currency, endHeight uint64) (api.ContractMetadata, error)
RenewContract(ctx context.Context, fcid types.FileContractID, endHeight uint64, renterFunds, minNewCollateral, maxFundAmount types.Currency, expectedNewStorage uint64) (api.ContractMetadata, error)
Host(ctx context.Context, hostKey types.PublicKey) (api.Host, error)
RecordContractSetChurnMetric(ctx context.Context, metrics ...api.ContractSetChurnMetric) error
SearchHosts(ctx context.Context, opts api.SearchHostOptions) ([]api.Host, error)
Expand All @@ -100,7 +100,6 @@ type Worker interface {
Contracts(ctx context.Context, hostTimeout time.Duration) (api.ContractsResponse, error)
RHPBroadcast(ctx context.Context, fcid types.FileContractID) (err error)
RHPPriceTable(ctx context.Context, hostKey types.PublicKey, siamuxAddr string, timeout time.Duration) (api.HostPriceTable, error)
RHPRenew(ctx context.Context, fcid types.FileContractID, endHeight uint64, hk types.PublicKey, hostIP string, hostAddress, renterAddress types.Address, renterFunds, minNewCollateral, maxFundAmount types.Currency, expectedNewStorage, windowSize uint64) (api.RHPRenewResponse, error)
RHPScan(ctx context.Context, hostKey types.PublicKey, hostIP string, timeout time.Duration) (api.RHPScanResponse, error)
}

Expand Down Expand Up @@ -307,7 +306,7 @@ func (c *Contractor) refreshContract(ctx *mCtx, w Worker, contract api.Contract,
maxFundAmount := budget.Add(rev.ValidRenterPayout())

// renew the contract
resp, err := w.RHPRenew(ctx, contract.ID, contract.EndHeight(), hk, contract.SiamuxAddr, settings.Address, ctx.state.Address, renterFunds, minNewCollateral, maxFundAmount, expectedNewStorage, settings.WindowSize)
renewal, err := c.bus.RenewContract(ctx, contract.ID, contract.EndHeight(), renterFunds, minNewCollateral, maxFundAmount, expectedNewStorage)
if err != nil {
if strings.Contains(err.Error(), "new collateral is too low") {
logger.Infow("refresh failed: contract wouldn't have enough collateral after refresh",
Expand All @@ -326,25 +325,16 @@ func (c *Contractor) refreshContract(ctx *mCtx, w Worker, contract api.Contract,
}

// update the budget
*budget = budget.Sub(resp.FundAmount)

// persist the contract
refreshedContract, err := c.bus.AddRenewedContract(ctx, resp.Contract, resp.ContractPrice, renterFunds, cs.BlockHeight, contract.ID, api.ContractStatePending)
if err != nil {
logger.Errorw("adding refreshed contract failed", zap.Error(err), "hk", hk, "fcid", fcid)
return api.ContractMetadata{}, false, err
}
*budget = budget.Sub(renewal.TotalCost)

// add to renewed set
newCollateral := resp.Contract.Revision.MissedHostPayout().Sub(resp.ContractPrice)
logger.Infow("refresh succeeded",
"fcid", refreshedContract.ID,
"renewedFrom", contract.ID,
"fcid", renewal.ID,
"renewedFrom", renewal.RenewedFrom,
"renterFunds", renterFunds.String(),
"minNewCollateral", minNewCollateral.String(),
"newCollateral", newCollateral.String(),
)
return refreshedContract, true, nil
return renewal, true, nil
}

func (c *Contractor) renewContract(ctx *mCtx, w Worker, contract api.Contract, host api.Host, budget *types.Currency, logger *zap.SugaredLogger) (cm api.ContractMetadata, proceed bool, err error) {
Expand All @@ -354,11 +344,9 @@ func (c *Contractor) renewContract(ctx *mCtx, w Worker, contract api.Contract, h
logger = logger.With("to_renew", contract.ID, "hk", contract.HostKey, "hostVersion", host.Settings.Version, "hostRelease", host.Settings.Release)

// convenience variables
settings := host.Settings
pt := host.PriceTable.HostPriceTable
fcid := contract.ID
rev := contract.Revision
hk := contract.HostKey

// fetch consensus state
cs, err := c.bus.ConsensusState(ctx)
Expand Down Expand Up @@ -388,7 +376,7 @@ func (c *Contractor) renewContract(ctx *mCtx, w Worker, contract api.Contract, h
expectedNewStorage := renterFundsToExpectedStorage(renterFunds, endHeight-cs.BlockHeight, pt)

// renew the contract
resp, err := w.RHPRenew(ctx, fcid, endHeight, hk, contract.SiamuxAddr, settings.Address, ctx.state.Address, renterFunds, types.ZeroCurrency, *budget, expectedNewStorage, settings.WindowSize)
renewal, err := c.bus.RenewContract(ctx, fcid, endHeight, renterFunds, types.ZeroCurrency, *budget, expectedNewStorage)
if err != nil {
logger.Errorw(
"renewal failed",
Expand All @@ -404,24 +392,15 @@ func (c *Contractor) renewContract(ctx *mCtx, w Worker, contract api.Contract, h
}

// update the budget
*budget = budget.Sub(resp.FundAmount)

// persist the contract
renewedContract, err := c.bus.AddRenewedContract(ctx, resp.Contract, resp.ContractPrice, renterFunds, cs.BlockHeight, fcid, api.ContractStatePending)
if err != nil {
logger.Errorw(fmt.Sprintf("renewal failed to persist, err: %v", err))
return api.ContractMetadata{}, false, err
}
*budget = budget.Sub(renewal.TotalCost)

newCollateral := resp.Contract.Revision.MissedHostPayout().Sub(resp.ContractPrice)
logger.Infow(
"renewal succeeded",
"fcid", renewedContract.ID,
"renewedFrom", fcid,
"fcid", renewal.ID,
"renewedFrom", renewal.RenewedFrom,
"renterFunds", renterFunds.String(),
"newCollateral", newCollateral.String(),
)
return renewedContract, true, nil
return renewal, true, nil
}

// broadcastRevisions broadcasts contract revisions from the current set of
Expand Down
1 change: 0 additions & 1 deletion autopilot/workerpool.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ type Worker interface {
RHPBroadcast(ctx context.Context, fcid types.FileContractID) (err error)
RHPPriceTable(ctx context.Context, hostKey types.PublicKey, siamuxAddr string, timeout time.Duration) (api.HostPriceTable, error)
RHPPruneContract(ctx context.Context, fcid types.FileContractID, timeout time.Duration) (pruned, remaining uint64, err error)
RHPRenew(ctx context.Context, fcid types.FileContractID, endHeight uint64, hk types.PublicKey, hostIP string, hostAddress, renterAddress types.Address, renterFunds, minNewCollateral, maxFundAmount types.Currency, expectedStorage, windowSize uint64) (api.RHPRenewResponse, error)
RHPScan(ctx context.Context, hostKey types.PublicKey, hostIP string, timeout time.Duration) (api.RHPScanResponse, error)
}

Expand Down
Loading

0 comments on commit 2ab36bb

Please sign in to comment.