Skip to content

Commit

Permalink
Merge pull request #504 from SiaFoundation/nate/refactor-rhp-settings
Browse files Browse the repository at this point in the history
Move settings and price table into config manager
  • Loading branch information
n8maninger authored Nov 19, 2024
2 parents bd91bb9 + cf191e2 commit 375fb76
Show file tree
Hide file tree
Showing 16 changed files with 231 additions and 204 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
default: patch
---

# Move RHP2 and RHP3 settings into the config manager to be consistent with RHP4
33 changes: 21 additions & 12 deletions cmd/hostd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,15 @@ func runRootCmd(ctx context.Context, cfg config.Config, walletKey types.PrivateK
}
defer rhp3Listener.Close()

_, rhp3PortStr, err := net.SplitHostPort(rhp3Listener.Addr().String())
if err != nil {
return fmt.Errorf("failed to parse rhp3 port: %w", err)
}
rhp3Port, err := strconv.ParseUint(rhp3PortStr, 10, 16)
if err != nil {
return fmt.Errorf("failed to parse rhp3 port: %w", err)
}

syncerAddr := syncerListener.Addr().String()
if cfg.Syncer.EnableUPnP {
_, portStr, _ := net.SplitHostPort(cfg.Syncer.Address)
Expand Down Expand Up @@ -253,42 +262,42 @@ func runRootCmd(ctx context.Context, cfg config.Config, walletKey types.PrivateK

am := alerts.NewManager(alerts.WithEventReporter(wr), alerts.WithLog(log.Named("alerts")))

cfm, err := settings.NewConfigManager(hostKey, store, cm, s, wm, settings.WithAlertManager(am), settings.WithLog(log.Named("settings")))
if err != nil {
return fmt.Errorf("failed to create settings manager: %w", err)
}
defer cfm.Close()

vm, err := storage.NewVolumeManager(store, storage.WithLogger(log.Named("volumes")), storage.WithAlerter(am))
if err != nil {
return fmt.Errorf("failed to create storage manager: %w", err)
}
defer vm.Close()

sm, err := settings.NewConfigManager(hostKey, store, cm, s, vm, wm, settings.WithAlertManager(am), settings.WithRHP3Port(uint16(rhp3Port)), settings.WithLog(log.Named("settings")))
if err != nil {
return fmt.Errorf("failed to create settings manager: %w", err)
}
defer sm.Close()

contractManager, err := contracts.NewManager(store, vm, cm, s, wm, contracts.WithLog(log.Named("contracts")), contracts.WithAlerter(am))
if err != nil {
return fmt.Errorf("failed to create contracts manager: %w", err)
}
defer contractManager.Close()

index, err := index.NewManager(store, cm, contractManager, wm, cfm, vm, index.WithLog(log.Named("index")), index.WithBatchSize(cfg.Consensus.IndexBatchSize))
index, err := index.NewManager(store, cm, contractManager, wm, sm, vm, index.WithLog(log.Named("index")), index.WithBatchSize(cfg.Consensus.IndexBatchSize))
if err != nil {
return fmt.Errorf("failed to create index manager: %w", err)
}
defer index.Close()

dr := rhp.NewDataRecorder(store, log.Named("data"))

rhp2, err := rhp2.NewSessionHandler(rhp2Listener, hostKey, rhp3Listener.Addr().String(), cm, s, wm, contractManager, cfm, vm, rhp2.WithDataMonitor(dr), rhp2.WithLog(log.Named("rhp2")))
rhp2, err := rhp2.NewSessionHandler(rhp2Listener, hostKey, cm, s, wm, contractManager, sm, vm, rhp2.WithDataMonitor(dr), rhp2.WithLog(log.Named("rhp2")))
if err != nil {
return fmt.Errorf("failed to create rhp2 session handler: %w", err)
}
go rhp2.Serve()
defer rhp2.Close()

registry := registry.NewManager(hostKey, store, log.Named("registry"))
accounts := accounts.NewManager(store, cfm)
rhp3, err := rhp3.NewSessionHandler(rhp3Listener, hostKey, cm, s, wm, accounts, contractManager, registry, vm, cfm, rhp3.WithDataMonitor(dr), rhp3.WithSessionReporter(sr), rhp3.WithLog(log.Named("rhp3")))
accounts := accounts.NewManager(store, sm)
rhp3, err := rhp3.NewSessionHandler(rhp3Listener, hostKey, cm, s, wm, accounts, contractManager, registry, vm, sm, rhp3.WithDataMonitor(dr), rhp3.WithSessionReporter(sr), rhp3.WithLog(log.Named("rhp3")))
if err != nil {
return fmt.Errorf("failed to create rhp3 session handler: %w", err)
}
Expand All @@ -304,7 +313,7 @@ func runRootCmd(ctx context.Context, cfg config.Config, walletKey types.PrivateK
}
if !cfg.Explorer.Disable {
ex := explorer.New(cfg.Explorer.URL)
pm, err := pin.NewManager(store, cfm, ex, pin.WithLogger(log.Named("pin")))
pm, err := pin.NewManager(store, sm, ex, pin.WithLogger(log.Named("pin")))
if err != nil {
return fmt.Errorf("failed to create pin manager: %w", err)
}
Expand All @@ -314,7 +323,7 @@ func runRootCmd(ctx context.Context, cfg config.Config, walletKey types.PrivateK

web := http.Server{
Handler: webRouter{
api: jape.BasicAuth(cfg.HTTP.Password)(api.NewServer(cfg.Name, hostKey.PublicKey(), cm, s, accounts, contractManager, vm, wm, store, cfm, index, apiOpts...)),
api: jape.BasicAuth(cfg.HTTP.Password)(api.NewServer(cfg.Name, hostKey.PublicKey(), cm, s, accounts, contractManager, vm, wm, store, sm, index, apiOpts...)),
ui: hostd.Handler(),
},
ReadTimeout: 30 * time.Second,
Expand Down
4 changes: 2 additions & 2 deletions host/settings/announce_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func TestAutoAnnounce(t *testing.T) {
}
defer storage.Close()

sm, err := settings.NewConfigManager(hostKey, node.Store, node.Chain, node.Syncer, wm, settings.WithLog(log.Named("settings")), settings.WithAnnounceInterval(50))
sm, err := settings.NewConfigManager(hostKey, node.Store, node.Chain, node.Syncer, vm, wm, settings.WithLog(log.Named("settings")), settings.WithAnnounceInterval(50))
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -186,7 +186,7 @@ func TestAutoAnnounceV2(t *testing.T) {
}
defer storage.Close()

sm, err := settings.NewConfigManager(hostKey, node.Store, node.Chain, node.Syncer, wm, settings.WithLog(log.Named("settings")), settings.WithAnnounceInterval(50))
sm, err := settings.NewConfigManager(hostKey, node.Store, node.Chain, node.Syncer, vm, wm, settings.WithLog(log.Named("settings")), settings.WithAnnounceInterval(50))
if err != nil {
t.Fatal(err)
}
Expand Down
8 changes: 8 additions & 0 deletions host/settings/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,11 @@ func WithInitialSettings(settings Settings) Option {
c.initialSettings = settings
}
}

// WithRHP3Port sets the port that the host is listening for
// RHP3 connections on. This is part of the RHP2 settings.
func WithRHP3Port(port uint16) Option {
return func(c *ConfigManager) {
c.rhp3Port = port
}
}
4 changes: 2 additions & 2 deletions host/settings/pin/pin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func TestPinnedFields(t *testing.T) {
currency: "usd",
}

sm, err := settings.NewConfigManager(types.GeneratePrivateKey(), node.Store, node.Chain, node.Syncer, nil)
sm, err := settings.NewConfigManager(types.GeneratePrivateKey(), node.Store, node.Chain, node.Syncer, nil, nil)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -218,7 +218,7 @@ func TestAutomaticUpdate(t *testing.T) {
currency: "usd",
}

sm, err := settings.NewConfigManager(types.GeneratePrivateKey(), node.Store, node.Chain, node.Syncer, nil)
sm, err := settings.NewConfigManager(types.GeneratePrivateKey(), node.Store, node.Chain, node.Syncer, nil, nil)
if err != nil {
t.Fatal(err)
}
Expand Down
154 changes: 142 additions & 12 deletions host/settings/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,25 @@ package settings

import (
"crypto/ed25519"
"crypto/tls"
"errors"
"fmt"
"net"
"strconv"
"strings"
"sync"
"time"

"go.sia.tech/core/consensus"
proto2 "go.sia.tech/core/rhp/v2"
proto3 "go.sia.tech/core/rhp/v3"
"go.sia.tech/core/types"
"go.sia.tech/hostd/alerts"
"go.sia.tech/hostd/build"
"go.sia.tech/hostd/internal/threadgroup"
rhp2 "go.sia.tech/hostd/rhp/v2"
"go.uber.org/zap"
"golang.org/x/time/rate"
"lukechampine.com/frand"
)

const (
Expand Down Expand Up @@ -67,6 +72,11 @@ type (
BroadcastV2TransactionSet(types.ChainIndex, []types.V2Transaction)
}

// Storage provides information about the host's storage capacity
Storage interface {
Usage() (used, total uint64, _ error)
}

// A Wallet manages Siacoins and funds transactions
Wallet interface {
Address() types.Address
Expand Down Expand Up @@ -135,9 +145,10 @@ type (
a Alerts
log *zap.Logger

chain ChainManager
syncer Syncer
wallet Wallet
chain ChainManager
syncer Syncer
storage Storage
wallet Wallet

mu sync.Mutex // guards the following fields
settings Settings // in-memory cache of the host's settings
Expand All @@ -150,7 +161,7 @@ type (
lastIPv4 net.IP
lastIPv6 net.IP

rhp3WSTLS *tls.Config
rhp3Port uint16

tg *threadgroup.ThreadGroup
}
Expand Down Expand Up @@ -258,18 +269,138 @@ func (m *ConfigManager) BandwidthLimiters() (ingress, egress *rate.Limiter) {
return m.ingressLimit, m.egressLimit
}

// AcceptingContracts returns true if the host is currently accepting contracts
func (m *ConfigManager) AcceptingContracts() bool {
s := m.Settings()
return s.AcceptingContracts
}

// RHP2Settings returns the host's current RHP2 settings
func (m *ConfigManager) RHP2Settings() (proto2.HostSettings, error) {
usedSectors, totalSectors, err := m.storage.Usage()
if err != nil {
return proto2.HostSettings{}, fmt.Errorf("failed to get storage usage: %w", err)
}
settings := m.Settings()

return proto2.HostSettings{
// build info
Release: "hostd " + build.Version(),
// protocol version
Version: rhp2.Version,

// host info
Address: m.wallet.Address(),
SiaMuxPort: strconv.FormatUint(uint64(m.rhp3Port), 10),
NetAddress: settings.NetAddress,
TotalStorage: totalSectors * proto2.SectorSize,
RemainingStorage: (totalSectors - usedSectors) * proto2.SectorSize,

// network defaults
MaxDownloadBatchSize: rhp2.DefaultBatchSize,
MaxReviseBatchSize: rhp2.DefaultBatchSize,
SectorSize: proto2.SectorSize,
WindowSize: settings.WindowSize,

// contract formation
AcceptingContracts: settings.AcceptingContracts,
MaxDuration: settings.MaxContractDuration,
ContractPrice: settings.ContractPrice,

// rpc prices
BaseRPCPrice: settings.BaseRPCPrice,
SectorAccessPrice: settings.SectorAccessPrice,
Collateral: settings.StoragePrice.Mul64(uint64(settings.CollateralMultiplier * 1000)).Div64(1000),
MaxCollateral: settings.MaxCollateral,
StoragePrice: settings.StoragePrice,
DownloadBandwidthPrice: settings.EgressPrice,
UploadBandwidthPrice: settings.IngressPrice,

// ea settings
MaxEphemeralAccountBalance: settings.MaxAccountBalance,
EphemeralAccountExpiry: settings.AccountExpiry,

RevisionNumber: settings.Revision,
}, nil
}

// RHP3PriceTable returns the host's current RHP3 price table
func (m *ConfigManager) RHP3PriceTable() (proto3.HostPriceTable, error) {
settings := m.Settings()

fee := m.chain.RecommendedFee()
currentHeight := m.chain.TipState().Index.Height
oneHasting := types.NewCurrency64(1)

return proto3.HostPriceTable{
UID: frand.Entropy128(),
HostBlockHeight: currentHeight,
Validity: settings.PriceTableValidity,

// ephemeral account costs
AccountBalanceCost: oneHasting,
FundAccountCost: oneHasting,
UpdatePriceTableCost: oneHasting,

// MDM costs
HasSectorBaseCost: oneHasting,
MemoryTimeCost: oneHasting,
DropSectorsBaseCost: oneHasting,
DropSectorsUnitCost: oneHasting,
SwapSectorBaseCost: oneHasting,

ReadBaseCost: settings.SectorAccessPrice,
ReadLengthCost: oneHasting,
WriteBaseCost: settings.SectorAccessPrice,
WriteLengthCost: oneHasting,
WriteStoreCost: settings.StoragePrice,
InitBaseCost: settings.BaseRPCPrice,

// bandwidth costs
DownloadBandwidthCost: settings.EgressPrice,
UploadBandwidthCost: settings.IngressPrice,

// LatestRevisionCost is set to a reasonable base + the estimated
// bandwidth cost of downloading a filecontract. This isn't perfect but
// at least scales a bit as the host updates their download bandwidth
// prices.
LatestRevisionCost: settings.BaseRPCPrice.Add(settings.EgressPrice.Mul64(2048)),

// Contract Formation/Renewal related fields
ContractPrice: settings.ContractPrice,
CollateralCost: settings.StoragePrice.Mul64(uint64(settings.CollateralMultiplier * 1000)).Div64(1000),
MaxCollateral: settings.MaxCollateral,
MaxDuration: settings.MaxContractDuration,
WindowSize: settings.WindowSize,
RenewContractCost: types.Siacoins(100).Div64(1e9),

// Registry related fields.
RegistryEntriesLeft: 0,
RegistryEntriesTotal: 0,

// Subscription related fields.
SubscriptionMemoryCost: oneHasting,
SubscriptionNotificationCost: oneHasting,

// TxnFee related fields.
TxnFeeMinRecommended: fee.Div64(3),
TxnFeeMaxRecommended: fee,
}, nil
}

// NewConfigManager initializes a new config manager
func NewConfigManager(hostKey types.PrivateKey, store Store, cm ChainManager, s Syncer, wm Wallet, opts ...Option) (*ConfigManager, error) {
func NewConfigManager(hostKey types.PrivateKey, store Store, cm ChainManager, s Syncer, sm Storage, wm Wallet, opts ...Option) (*ConfigManager, error) {
m := &ConfigManager{
announceInterval: 144 * 90, // 90 days
validateNetAddress: true,
hostKey: hostKey,
initialSettings: DefaultSettings,

store: store,
chain: cm,
syncer: s,
wallet: wm,
store: store,
chain: cm,
syncer: s,
storage: sm,
wallet: wm,

log: zap.NewNop(),
a: alerts.NewNop(),
Expand All @@ -279,8 +410,7 @@ func NewConfigManager(hostKey types.PrivateKey, store Store, cm ChainManager, s
ingressLimit: rate.NewLimiter(rate.Inf, defaultBurstSize),
egressLimit: rate.NewLimiter(rate.Inf, defaultBurstSize),

// rhp3 WebSocket TLS
rhp3WSTLS: &tls.Config{},
rhp3Port: 9983,
}

for _, opt := range opts {
Expand Down
2 changes: 1 addition & 1 deletion host/settings/settings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func TestSettings(t *testing.T) {
}
defer contracts.Close()

sm, err := settings.NewConfigManager(hostKey, node.Store, node.Chain, node.Syncer, wm, settings.WithLog(log.Named("settings")), settings.WithAnnounceInterval(50), settings.WithValidateNetAddress(false))
sm, err := settings.NewConfigManager(hostKey, node.Store, node.Chain, node.Syncer, vm, wm, settings.WithLog(log.Named("settings")), settings.WithAnnounceInterval(50), settings.WithValidateNetAddress(false))
if err != nil {
t.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion internal/testutil/testutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ func NewHostNode(t *testing.T, pk types.PrivateKey, network *consensus.Network,
initialSettings.AcceptingContracts = true
initialSettings.NetAddress = "127.0.0.1:9981"
initialSettings.WindowSize = 10
sm, err := settings.NewConfigManager(pk, cn.Store, cn.Chain, cn.Syncer, wm, settings.WithAnnounceInterval(10), settings.WithValidateNetAddress(false), settings.WithInitialSettings(initialSettings))
sm, err := settings.NewConfigManager(pk, cn.Store, cn.Chain, cn.Syncer, vm, wm, settings.WithAnnounceInterval(10), settings.WithValidateNetAddress(false), settings.WithInitialSettings(initialSettings))
if err != nil {
t.Fatal(err)
}
Expand Down
Loading

0 comments on commit 375fb76

Please sign in to comment.