Skip to content

Commit

Permalink
Merge branch 'pj/host-infos' of github.com:SiaFoundation/renterd into…
Browse files Browse the repository at this point in the history
… pj/host-infos
  • Loading branch information
peterjan committed Mar 27, 2024
2 parents 2f42d58 + 39c9a5d commit c58cc7a
Show file tree
Hide file tree
Showing 28 changed files with 228 additions and 266 deletions.
76 changes: 69 additions & 7 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 Down Expand Up @@ -41,12 +43,12 @@ var (
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 @@ -70,7 +72,7 @@ type (
// HostResponse is the response type for the GET
// /api/autopilot/host/:hostkey endpoint.
HostResponse struct {
Host hostdb.Host `json:"host"`
Host Host `json:"host"`
Checks *HostChecks `json:"checks,omitempty"`
}

Expand Down Expand Up @@ -146,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 @@ -187,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
11 changes: 5 additions & 6 deletions autopilot/autopilot.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
"go.sia.tech/renterd/alerts"
"go.sia.tech/renterd/api"
"go.sia.tech/renterd/build"
"go.sia.tech/renterd/hostdb"
"go.sia.tech/renterd/internal/utils"
"go.sia.tech/renterd/object"
"go.sia.tech/renterd/wallet"
Expand Down Expand Up @@ -54,7 +53,7 @@ type Bus interface {

// hostdb
Host(ctx context.Context, hostKey types.PublicKey) (api.Host, error)
HostsForScanning(ctx context.Context, opts api.HostsForScanningOptions) ([]hostdb.HostAddress, error)
HostsForScanning(ctx context.Context, opts api.HostsForScanningOptions) ([]api.HostAddress, error)
RemoveOfflineHosts(ctx context.Context, minRecentScanFailures uint64, maxDowntime time.Duration) (uint64, error)
SearchHosts(ctx context.Context, opts api.SearchHostOptions) ([]api.Host, error)
UpdateHostCheck(ctx context.Context, autopilotID string, hostKey types.PublicKey, hostCheck api.HostCheck) error
Expand Down Expand Up @@ -701,7 +700,7 @@ func (ap *Autopilot) hostHandlerGET(jc jape.Context) {
check, ok := hi.Checks[ap.id]
if ok {
jc.Encode(api.HostResponse{
Host: hi.Host,
Host: hi,
Checks: &api.HostChecks{
Gouging: check.Gouging.Gouging(),
GougingBreakdown: check.Gouging,
Expand All @@ -714,7 +713,7 @@ func (ap *Autopilot) hostHandlerGET(jc jape.Context) {
return
}

jc.Encode(api.HostResponse{Host: hi.Host})
jc.Encode(api.HostResponse{Host: hi})
}

func (ap *Autopilot) hostsHandlerPOST(jc jape.Context) {
Expand Down Expand Up @@ -747,7 +746,7 @@ func (ap *Autopilot) hostsHandlerPOST(jc jape.Context) {
for i, host := range hosts {
if check, ok := host.Checks[ap.id]; ok {
resps[i] = api.HostResponse{
Host: host.Host,
Host: host,
Checks: &api.HostChecks{
Gouging: check.Gouging.Gouging(),
GougingBreakdown: check.Gouging,
Expand All @@ -758,7 +757,7 @@ func (ap *Autopilot) hostsHandlerPOST(jc jape.Context) {
},
}
} else {
resps[i] = api.HostResponse{Host: host.Host}
resps[i] = api.HostResponse{Host: host}
}
}
jc.Encode(resps)
Expand Down
47 changes: 22 additions & 25 deletions autopilot/autopilot_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
rhpv3 "go.sia.tech/core/rhp/v3"
"go.sia.tech/core/types"
"go.sia.tech/renterd/api"
"go.sia.tech/renterd/hostdb"
)

func TestOptimiseGougingSetting(t *testing.T) {
Expand All @@ -18,32 +17,30 @@ func TestOptimiseGougingSetting(t *testing.T) {
for i := 0; i < 10; i++ {
hosts = append(hosts, api.Host{

Host: hostdb.Host{
KnownSince: time.Unix(0, 0),
PriceTable: hostdb.HostPriceTable{
HostPriceTable: rhpv3.HostPriceTable{
CollateralCost: types.Siacoins(1),
MaxCollateral: types.Siacoins(1000),
},
KnownSince: time.Unix(0, 0),
PriceTable: api.HostPriceTable{
HostPriceTable: rhpv3.HostPriceTable{
CollateralCost: types.Siacoins(1),
MaxCollateral: types.Siacoins(1000),
},
Settings: rhpv2.HostSettings{
AcceptingContracts: true,
Collateral: types.Siacoins(1),
MaxCollateral: types.Siacoins(1000),
Version: "1.6.0",
},
Interactions: hostdb.Interactions{
Uptime: time.Hour * 1000,
LastScan: time.Now(),
LastScanSuccess: true,
SecondToLastScanSuccess: true,
TotalScans: 100,
},
LastAnnouncement: time.Unix(0, 0),
Scanned: true,
},
Blocked: false,
Checks: nil,
Settings: rhpv2.HostSettings{
AcceptingContracts: true,
Collateral: types.Siacoins(1),
MaxCollateral: types.Siacoins(1000),
Version: "1.6.0",
},
Interactions: api.HostInteractions{
Uptime: time.Hour * 1000,
LastScan: time.Now(),
LastScanSuccess: true,
SecondToLastScanSuccess: true,
TotalScans: 100,
},
LastAnnouncement: time.Unix(0, 0),
Scanned: true,
Blocked: false,
Checks: nil,
})
}

Expand Down
11 changes: 5 additions & 6 deletions autopilot/contractor.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
rhpv3 "go.sia.tech/core/rhp/v3"
"go.sia.tech/core/types"
"go.sia.tech/renterd/api"
"go.sia.tech/renterd/hostdb"
"go.sia.tech/renterd/internal/utils"
"go.sia.tech/renterd/wallet"
"go.sia.tech/renterd/worker"
Expand Down Expand Up @@ -103,7 +102,7 @@ type (
}

scoredHost struct {
host hostdb.Host
host api.Host
score float64
}

Expand Down Expand Up @@ -758,7 +757,7 @@ func (c *contractor) runContractChecks(ctx context.Context, contracts []api.Cont
}

// decide whether the contract is still good
ci := contractInfo{contract: contract, priceTable: host.Host.PriceTable.HostPriceTable, settings: host.Host.Settings}
ci := contractInfo{contract: contract, priceTable: host.PriceTable.HostPriceTable, settings: host.Settings}
usable, recoverable, refresh, renew, reasons := c.isUsableContract(state.cfg, state, ci, bh, ipFilter)
ci.usable = usable
ci.recoverable = recoverable
Expand Down Expand Up @@ -1320,7 +1319,7 @@ func (c *contractor) candidateHosts(ctx context.Context, hosts []api.Host, usedH
h.PriceTable.HostBlockHeight = cs.BlockHeight
hc := checkHost(state.cfg, state.rs, gc, h, minScore, storedData[h.PublicKey])
if hc.Usability.IsUsable() {
candidates = append(candidates, scoredHost{h.Host, hc.Score.Score()})
candidates = append(candidates, scoredHost{h, hc.Score.Score()})
continue
}

Expand Down Expand Up @@ -1502,7 +1501,7 @@ func (c *contractor) refreshContract(ctx context.Context, w Worker, ci contractI
return refreshedContract, true, nil
}

func (c *contractor) formContract(ctx context.Context, w Worker, host hostdb.Host, minInitialContractFunds, maxInitialContractFunds types.Currency, budget *types.Currency) (cm api.ContractMetadata, proceed bool, err error) {
func (c *contractor) formContract(ctx context.Context, w Worker, host api.Host, minInitialContractFunds, maxInitialContractFunds types.Currency, budget *types.Currency) (cm api.ContractMetadata, proceed bool, err error) {
// convenience variables
state := c.ap.State()
hk := host.PublicKey
Expand Down Expand Up @@ -1629,7 +1628,7 @@ func initialContractFundingMinMax(cfg api.AutopilotConfig) (min types.Currency,
return
}

func refreshPriceTable(ctx context.Context, w Worker, host *hostdb.Host) error {
func refreshPriceTable(ctx context.Context, w Worker, host *api.Host) error {
// return early if the host's pricetable is not expired yet
if time.Now().Before(host.PriceTable.Expiry) {
return nil
Expand Down
14 changes: 7 additions & 7 deletions autopilot/host_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
rhpv2 "go.sia.tech/core/rhp/v2"
rhpv3 "go.sia.tech/core/rhp/v3"
"go.sia.tech/core/types"
"go.sia.tech/renterd/hostdb"
"go.sia.tech/renterd/api"
"lukechampine.com/frand"
)

Expand Down Expand Up @@ -40,20 +40,20 @@ func TestHost(t *testing.T) {
}
}

func newTestHosts(n int) []hostdb.Host {
hosts := make([]hostdb.Host, n)
func newTestHosts(n int) []api.Host {
hosts := make([]api.Host, n)
for i := 0; i < n; i++ {
hosts[i] = newTestHost(randomHostKey(), newTestHostPriceTable(), newTestHostSettings())
}
return hosts
}

func newTestHost(hk types.PublicKey, pt rhpv3.HostPriceTable, settings rhpv2.HostSettings) hostdb.Host {
return hostdb.Host{
func newTestHost(hk types.PublicKey, pt rhpv3.HostPriceTable, settings rhpv2.HostSettings) api.Host {
return api.Host{
NetAddress: randomIP().String(),
KnownSince: time.Now(),
LastAnnouncement: time.Now(),
Interactions: hostdb.Interactions{
Interactions: api.HostInteractions{
TotalScans: 2,
LastScan: time.Now().Add(-time.Minute),
LastScanSuccess: true,
Expand All @@ -65,7 +65,7 @@ func newTestHost(hk types.PublicKey, pt rhpv3.HostPriceTable, settings rhpv2.Hos
FailedInteractions: 0,
},
PublicKey: hk,
PriceTable: hostdb.HostPriceTable{HostPriceTable: pt, Expiry: time.Now().Add(time.Minute)},
PriceTable: api.HostPriceTable{HostPriceTable: pt, Expiry: time.Now().Add(time.Minute)},
Settings: settings,
Scanned: true,
}
Expand Down
2 changes: 1 addition & 1 deletion autopilot/hostfilter.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ func checkHost(cfg api.AutopilotConfig, rs api.RedundancySettings, gc worker.Gou
// not gouging, this because the core package does not have overflow
// checks in its cost calculations needed to calculate the period
// cost
sb = hostScore(cfg, h.Host, storedData, rs.Redundancy())
sb = hostScore(cfg, h, storedData, rs.Redundancy())
if sb.Score() < minScore {
ub.LowScore = true
}
Expand Down
8 changes: 4 additions & 4 deletions autopilot/hosts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"testing"

"go.sia.tech/core/types"
"go.sia.tech/renterd/hostdb"
"go.sia.tech/renterd/api"
"lukechampine.com/frand"
)

Expand All @@ -18,7 +18,7 @@ func TestScoredHostsRandSelectByScore(t *testing.T) {

var hosts scoredHosts
for hk, score := range hostToScores {
hosts = append(hosts, scoredHost{score: score, host: hostdb.Host{PublicKey: hk}})
hosts = append(hosts, scoredHost{score: score, host: api.Host{PublicKey: hk}})
}

for i := 0; i < 1000; i++ {
Expand Down Expand Up @@ -55,8 +55,8 @@ func TestScoredHostsRandSelectByScore(t *testing.T) {
// assert select is random on equal inputs
counts := make([]int, 2)
hosts = scoredHosts{
{score: .1, host: hostdb.Host{PublicKey: types.PublicKey{1}}},
{score: .1, host: hostdb.Host{PublicKey: types.PublicKey{2}}},
{score: .1, host: api.Host{PublicKey: types.PublicKey{1}}},
{score: .1, host: api.Host{PublicKey: types.PublicKey{2}}},
}
for i := 0; i < 100; i++ {
if hosts.randSelectByScore(1)[0].host.PublicKey == (types.PublicKey{1}) {
Expand Down
Loading

0 comments on commit c58cc7a

Please sign in to comment.