Skip to content

Commit

Permalink
Move host info to the bus (#1077)
Browse files Browse the repository at this point in the history
This PR gets rid of the contractor cache. It stores the host checks in
the bus and uses those when performing contract checks. To do so I
extended search hosts with the ability to filter on usability and
autopilot ID.

Closes #1034
  • Loading branch information
ChrisSchinnerl authored Mar 28, 2024
2 parents e31b792 + da9d3e7 commit 3f946f1
Show file tree
Hide file tree
Showing 33 changed files with 706 additions and 783 deletions.
1 change: 0 additions & 1 deletion .github/workflows/project-add.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,3 @@ jobs:
add-to-project:
uses: SiaFoundation/workflows/.github/workflows/project-add.yml@master
secrets: inherit

16 changes: 0 additions & 16 deletions api/autopilot.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"errors"

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

const (
Expand Down Expand Up @@ -119,21 +118,6 @@ type (
}
Recommendation *ConfigRecommendation `json:"recommendation,omitempty"`
}

// HostHandlerResponse is the response type for the /host/:hostkey endpoint.
HostHandlerResponse struct {
Host hostdb.Host `json:"host"`
Checks *HostHandlerResponseChecks `json:"checks,omitempty"`
}

HostHandlerResponseChecks struct {
Gouging bool `json:"gouging"`
GougingBreakdown HostGougingBreakdown `json:"gougingBreakdown"`
Score float64 `json:"score"`
ScoreBreakdown HostScoreBreakdown `json:"scoreBreakdown"`
Usable bool `json:"usable"`
UnusableReasons []string `json:"unusableReasons"`
}
)

func (c AutopilotConfig) Validate() error {
Expand Down
138 changes: 132 additions & 6 deletions api/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import (
"fmt"
"net/url"
"strings"
"time"

rhpv2 "go.sia.tech/core/rhp/v2"
rhpv3 "go.sia.tech/core/rhp/v3"
"go.sia.tech/core/types"
"go.sia.tech/renterd/hostdb"
)

const (
Expand All @@ -26,15 +28,27 @@ var (
ErrHostNotFound = errors.New("host doesn't exist in hostdb")
)

var (
ErrUsabilityHostBlocked = errors.New("host is blocked")
ErrUsabilityHostNotFound = errors.New("host not found")
ErrUsabilityHostOffline = errors.New("host is offline")
ErrUsabilityHostLowScore = errors.New("host's score is below minimum")
ErrUsabilityHostRedundantIP = errors.New("host has redundant IP")
ErrUsabilityHostPriceGouging = errors.New("host is price gouging")
ErrUsabilityHostNotAcceptingContracts = errors.New("host is not accepting contracts")
ErrUsabilityHostNotCompletingScan = errors.New("host is not completing scan")
ErrUsabilityHostNotAnnounced = errors.New("host is not announced")
)

type (
// HostsScanRequest is the request type for the /hosts/scans endpoint.
HostsScanRequest struct {
Scans []hostdb.HostScan `json:"scans"`
Scans []HostScan `json:"scans"`
}

// HostsPriceTablesRequest is the request type for the /hosts/pricetables endpoint.
HostsPriceTablesRequest struct {
PriceTableUpdates []hostdb.PriceTableUpdate `json:"priceTableUpdates"`
PriceTableUpdates []HostPriceTableUpdate `json:"priceTableUpdates"`
}

// HostsRemoveRequest is the request type for the /hosts/remove endpoint.
Expand All @@ -48,11 +62,28 @@ type (
SearchHostsRequest struct {
Offset int `json:"offset"`
Limit int `json:"limit"`
AutopilotID string `json:"autopilotID"`
FilterMode string `json:"filterMode"`
UsabilityMode string `json:"usabilityMode"`
AddressContains string `json:"addressContains"`
KeyIn []types.PublicKey `json:"keyIn"`
}

// HostResponse is the response type for the GET
// /api/autopilot/host/:hostkey endpoint.
HostResponse struct {
Host Host `json:"host"`
Checks *HostChecks `json:"checks,omitempty"`
}

HostChecks struct {
Gouging bool `json:"gouging"`
GougingBreakdown HostGougingBreakdown `json:"gougingBreakdown"`
Score float64 `json:"score"`
ScoreBreakdown HostScoreBreakdown `json:"scoreBreakdown"`
Usable bool `json:"usable"`
UnusableReasons []string `json:"unusableReasons,omitempty"`
}
)

type (
Expand Down Expand Up @@ -84,8 +115,10 @@ type (
}

SearchHostOptions struct {
AutopilotID string
AddressContains string
FilterMode string
UsabilityMode string
KeyIn []types.PublicKey
Limit int
Offset int
Expand Down Expand Up @@ -115,9 +148,54 @@ func (opts HostsForScanningOptions) Apply(values url.Values) {

type (
Host struct {
hostdb.Host
Blocked bool `json:"blocked"`
Checks map[string]HostCheck `json:"checks"`
KnownSince time.Time `json:"knownSince"`
LastAnnouncement time.Time `json:"lastAnnouncement"`
PublicKey types.PublicKey `json:"publicKey"`
NetAddress string `json:"netAddress"`
PriceTable HostPriceTable `json:"priceTable"`
Settings rhpv2.HostSettings `json:"settings"`
Interactions HostInteractions `json:"interactions"`
Scanned bool `json:"scanned"`
Blocked bool `json:"blocked"`
Checks map[string]HostCheck `json:"checks"`
}

HostAddress struct {
PublicKey types.PublicKey `json:"publicKey"`
NetAddress string `json:"netAddress"`
}

HostInteractions struct {
TotalScans uint64 `json:"totalScans"`
LastScan time.Time `json:"lastScan"`
LastScanSuccess bool `json:"lastScanSuccess"`
LostSectors uint64 `json:"lostSectors"`
SecondToLastScanSuccess bool `json:"secondToLastScanSuccess"`
Uptime time.Duration `json:"uptime"`
Downtime time.Duration `json:"downtime"`

SuccessfulInteractions float64 `json:"successfulInteractions"`
FailedInteractions float64 `json:"failedInteractions"`
}

HostScan struct {
HostKey types.PublicKey `json:"hostKey"`
Success bool
Timestamp time.Time
Settings rhpv2.HostSettings
PriceTable rhpv3.HostPriceTable
}

HostPriceTable struct {
rhpv3.HostPriceTable
Expiry time.Time `json:"expiry"`
}

HostPriceTableUpdate struct {
HostKey types.PublicKey `json:"hostKey"`
Success bool
Timestamp time.Time
PriceTable HostPriceTable
}

HostCheck struct {
Expand Down Expand Up @@ -156,6 +234,21 @@ type (
}
)

// IsAnnounced returns whether the host has been announced.
func (h Host) IsAnnounced() bool {
return !h.LastAnnouncement.IsZero()
}

// IsOnline returns whether a host is considered online.
func (h Host) IsOnline() bool {
if h.Interactions.TotalScans == 0 {
return false
} else if h.Interactions.TotalScans == 1 {
return h.Interactions.LastScanSuccess
}
return h.Interactions.LastScanSuccess || h.Interactions.SecondToLastScanSuccess
}

func (sb HostScoreBreakdown) String() string {
return fmt.Sprintf("Age: %v, Col: %v, Int: %v, SR: %v, UT: %v, V: %v, Pr: %v", sb.Age, sb.Collateral, sb.Interactions, sb.StorageRemaining, sb.Uptime, sb.Version, sb.Prices)
}
Expand Down Expand Up @@ -194,3 +287,36 @@ func (hgb HostGougingBreakdown) String() string {
func (sb HostScoreBreakdown) Score() float64 {
return sb.Age * sb.Collateral * sb.Interactions * sb.StorageRemaining * sb.Uptime * sb.Version * sb.Prices
}

func (ub HostUsabilityBreakdown) IsUsable() bool {
return !ub.Blocked && !ub.Offline && !ub.LowScore && !ub.RedundantIP && !ub.Gouging && !ub.NotAcceptingContracts && !ub.NotAnnounced && !ub.NotCompletingScan
}

func (ub HostUsabilityBreakdown) UnusableReasons() []string {
var reasons []string
if ub.Blocked {
reasons = append(reasons, ErrUsabilityHostBlocked.Error())
}
if ub.Offline {
reasons = append(reasons, ErrUsabilityHostOffline.Error())
}
if ub.LowScore {
reasons = append(reasons, ErrUsabilityHostLowScore.Error())
}
if ub.RedundantIP {
reasons = append(reasons, ErrUsabilityHostRedundantIP.Error())
}
if ub.Gouging {
reasons = append(reasons, ErrUsabilityHostPriceGouging.Error())
}
if ub.NotAcceptingContracts {
reasons = append(reasons, ErrUsabilityHostNotAcceptingContracts.Error())
}
if ub.NotAnnounced {
reasons = append(reasons, ErrUsabilityHostNotAnnounced.Error())
}
if ub.NotCompletingScan {
reasons = append(reasons, ErrUsabilityHostNotCompletingScan.Error())
}
return reasons
}
Loading

0 comments on commit 3f946f1

Please sign in to comment.