From 27362b1cbc8fcb270092e9bb93caecf09e8c22d4 Mon Sep 17 00:00:00 2001 From: Nate Date: Mon, 18 Nov 2024 12:06:44 -0800 Subject: [PATCH 1/2] cmd,settings,rhp: move settings and price table into config manager --- cmd/hostd/run.go | 33 ++++--- host/settings/announce_test.go | 4 +- host/settings/options.go | 8 ++ host/settings/pin/pin_test.go | 4 +- host/settings/settings.go | 154 ++++++++++++++++++++++++++++++--- host/settings/settings_test.go | 2 +- internal/testutil/testutil.go | 2 +- rhp/v2/rhp.go | 82 +++--------------- rhp/v2/rpc.go | 33 +++---- rhp/v2/rpc_test.go | 10 +-- rhp/v3/payments.go | 12 ++- rhp/v3/pricetable.go | 69 --------------- rhp/v3/rhp.go | 7 +- rhp/v3/rpc.go | 6 +- rhp/v3/rpc_test.go | 4 +- 15 files changed, 226 insertions(+), 204 deletions(-) diff --git a/cmd/hostd/run.go b/cmd/hostd/run.go index 543d1f27..29cab2ae 100644 --- a/cmd/hostd/run.go +++ b/cmd/hostd/run.go @@ -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) @@ -253,25 +262,25 @@ 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) } @@ -279,7 +288,7 @@ func runRootCmd(ctx context.Context, cfg config.Config, walletKey types.PrivateK 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) } @@ -287,8 +296,8 @@ func runRootCmd(ctx context.Context, cfg config.Config, walletKey types.PrivateK 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) } @@ -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) } @@ -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, diff --git a/host/settings/announce_test.go b/host/settings/announce_test.go index e6545997..115c4aa6 100644 --- a/host/settings/announce_test.go +++ b/host/settings/announce_test.go @@ -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) } @@ -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) } diff --git a/host/settings/options.go b/host/settings/options.go index d6199cde..129bd6fa 100644 --- a/host/settings/options.go +++ b/host/settings/options.go @@ -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 + } +} diff --git a/host/settings/pin/pin_test.go b/host/settings/pin/pin_test.go index 554217cc..4c0ea580 100644 --- a/host/settings/pin/pin_test.go +++ b/host/settings/pin/pin_test.go @@ -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) } @@ -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) } diff --git a/host/settings/settings.go b/host/settings/settings.go index 0cfc4cfe..45206e52 100644 --- a/host/settings/settings.go +++ b/host/settings/settings.go @@ -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 ( @@ -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 @@ -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 @@ -150,7 +161,7 @@ type ( lastIPv4 net.IP lastIPv6 net.IP - rhp3WSTLS *tls.Config + rhp3Port uint16 tg *threadgroup.ThreadGroup } @@ -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(), @@ -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 { diff --git a/host/settings/settings_test.go b/host/settings/settings_test.go index 5faa789c..c2e79b9b 100644 --- a/host/settings/settings_test.go +++ b/host/settings/settings_test.go @@ -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) } diff --git a/internal/testutil/testutil.go b/internal/testutil/testutil.go index 83e7f747..e1c32bcf 100644 --- a/internal/testutil/testutil.go +++ b/internal/testutil/testutil.go @@ -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) } diff --git a/rhp/v2/rhp.go b/rhp/v2/rhp.go index 3db917e3..50f31c2b 100644 --- a/rhp/v2/rhp.go +++ b/rhp/v2/rhp.go @@ -11,9 +11,7 @@ import ( "go.sia.tech/core/consensus" rhp2 "go.sia.tech/core/rhp/v2" "go.sia.tech/core/types" - "go.sia.tech/hostd/build" "go.sia.tech/hostd/host/contracts" - "go.sia.tech/hostd/host/settings" "go.sia.tech/hostd/internal/threadgroup" "go.sia.tech/hostd/rhp" "go.uber.org/zap" @@ -21,7 +19,8 @@ import ( ) const ( - defaultBatchSize = 20 * (1 << 20) // 20 MiB + // DefaultBatchSize is the maximum size in bytes of an RPC read and write request + DefaultBatchSize = 20 * (1 << 20) // 20 MiB // Version is the current version of the RHP2 protocol. Version = "1.6.0" @@ -49,10 +48,8 @@ type ( SectorRoots(id types.FileContractID) []types.Hash256 } - // A StorageManager manages the storage of sectors on disk. - StorageManager interface { - Usage() (used, total uint64, _ error) - + // Sectors reads and writes sectors to persistent storage + Sectors interface { // Write writes a sector to persistent storage. release should only be // called after the contract roots have been committed to prevent the // sector from being deleted. @@ -88,7 +85,7 @@ type ( // A SettingsReporter reports the host's current configuration. SettingsReporter interface { - Settings() settings.Settings + RHP2Settings() (rhp2.HostSettings, error) BandwidthLimiters() (ingress, egress *rate.Limiter) } @@ -102,7 +99,6 @@ type ( // manages renter sessions SessionHandler struct { privateKey types.PrivateKey - rhp3Port string listener net.Listener monitor rhp.DataMonitor @@ -115,7 +111,7 @@ type ( contracts ContractManager sessions SessionReporter settings SettingsReporter - storage StorageManager + sectors Sectors log *zap.Logger } ) @@ -210,55 +206,6 @@ func (sh *SessionHandler) Close() error { return sh.listener.Close() } -// Settings returns the host's current settings -func (sh *SessionHandler) Settings() (rhp2.HostSettings, error) { - settings := sh.settings.Settings() - usedSectors, totalSectors, err := sh.storage.Usage() - if err != nil { - return rhp2.HostSettings{}, fmt.Errorf("failed to get storage usage: %w", err) - } - - return rhp2.HostSettings{ - // build info - Release: "hostd " + build.Version(), - // protocol version - Version: Version, - - // host info - Address: sh.wallet.Address(), - SiaMuxPort: sh.rhp3Port, - NetAddress: settings.NetAddress, - TotalStorage: totalSectors * rhp2.SectorSize, - RemainingStorage: (totalSectors - usedSectors) * rhp2.SectorSize, - - // network defaults - MaxDownloadBatchSize: defaultBatchSize, - MaxReviseBatchSize: defaultBatchSize, - SectorSize: rhp2.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 -} - // Serve starts listening for new connections and blocks until closed func (sh *SessionHandler) Serve() error { for { @@ -287,25 +234,18 @@ func (sh *SessionHandler) LocalAddr() string { } // NewSessionHandler creates a new RHP2 SessionHandler -func NewSessionHandler(l net.Listener, hostKey types.PrivateKey, rhp3Addr string, cm ChainManager, s Syncer, wallet Wallet, contracts ContractManager, settings SettingsReporter, storage StorageManager, opts ...SessionHandlerOption) (*SessionHandler, error) { - _, rhp3Port, err := net.SplitHostPort(rhp3Addr) - if err != nil { - return nil, fmt.Errorf("failed to parse rhp3 addr: %w", err) - } - +func NewSessionHandler(l net.Listener, hostKey types.PrivateKey, cm ChainManager, s Syncer, wallet Wallet, contracts ContractManager, settings SettingsReporter, sectors Sectors, opts ...SessionHandlerOption) (*SessionHandler, error) { sh := &SessionHandler{ privateKey: hostKey, - rhp3Port: rhp3Port, listener: l, - - chain: cm, - syncer: s, - wallet: wallet, + chain: cm, + syncer: s, + wallet: wallet, contracts: contracts, settings: settings, - storage: storage, + sectors: sectors, log: zap.NewNop(), monitor: rhp.NewNoOpMonitor(), diff --git a/rhp/v2/rpc.go b/rhp/v2/rpc.go index bb057acd..d9476dd0 100644 --- a/rhp/v2/rpc.go +++ b/rhp/v2/rpc.go @@ -46,7 +46,7 @@ var ( ) func (sh *SessionHandler) rpcSettings(s *session, log *zap.Logger) (contracts.Usage, error) { - settings, err := sh.Settings() + settings, err := sh.settings.RHP2Settings() if err != nil { s.t.WriteResponseErr(ErrHostInternalError) return contracts.Usage{}, fmt.Errorf("failed to get host settings: %w", err) @@ -130,7 +130,13 @@ func (sh *SessionHandler) rpcFormContract(s *session, log *zap.Logger) (contract return contracts.Usage{}, ErrV2Hardfork } - if !sh.settings.Settings().AcceptingContracts { + settings, err := sh.settings.RHP2Settings() + if err != nil { + s.t.WriteResponseErr(ErrHostInternalError) + return contracts.Usage{}, fmt.Errorf("failed to get host settings: %w", err) + } + + if !settings.AcceptingContracts { s.t.WriteResponseErr(ErrNotAcceptingContracts) return contracts.Usage{}, ErrNotAcceptingContracts } @@ -153,11 +159,6 @@ func (sh *SessionHandler) rpcFormContract(s *session, log *zap.Logger) (contract renterPub := *(*types.PublicKey)(req.RenterKey.Key) // get the host's public key, current block height, and settings hostPub := sh.privateKey.PublicKey() - settings, err := sh.Settings() - if err != nil { - s.t.WriteResponseErr(ErrHostInternalError) - return contracts.Usage{}, fmt.Errorf("failed to get host settings: %w", err) - } // get the contract from the transaction set formationTxn, formationTxnSet := formationTxnSet[len(formationTxnSet)-1], formationTxnSet[:len(formationTxnSet)-1] @@ -268,7 +269,7 @@ func (sh *SessionHandler) rpcRenewAndClearContract(s *session, log *zap.Logger) return contracts.Usage{}, ErrV2Hardfork } - settings, err := sh.Settings() + settings, err := sh.settings.RHP2Settings() if err != nil { s.t.WriteResponseErr(ErrHostInternalError) return contracts.Usage{}, fmt.Errorf("failed to get host settings: %w", err) @@ -479,7 +480,7 @@ func (sh *SessionHandler) rpcSectorRoots(s *session, log *zap.Logger) (contracts return contracts.Usage{}, err } - settings, err := sh.Settings() + settings, err := sh.settings.RHP2Settings() if err != nil { s.t.WriteResponseErr(ErrHostInternalError) return contracts.Usage{}, fmt.Errorf("failed to get host settings: %w", err) @@ -569,7 +570,7 @@ func (sh *SessionHandler) rpcWrite(s *session, log *zap.Logger) (contracts.Usage s.t.WriteResponseErr(err) return contracts.Usage{}, err } - settings, err := sh.Settings() + settings, err := sh.settings.RHP2Settings() if err != nil { s.t.WriteResponseErr(ErrHostInternalError) return contracts.Usage{}, fmt.Errorf("failed to get settings: %w", err) @@ -633,7 +634,7 @@ func (sh *SessionHandler) rpcWrite(s *session, log *zap.Logger) (contracts.Usage } sector := (*[rhp2.SectorSize]byte)(action.Data) root := rhp2.SectorRoot(sector) - release, err := sh.storage.Write(root, sector) + release, err := sh.sectors.Write(root, sector) if err != nil { err := fmt.Errorf("append action: failed to write sector: %w", err) s.t.WriteResponseErr(err) @@ -661,7 +662,7 @@ func (sh *SessionHandler) rpcWrite(s *session, log *zap.Logger) (contracts.Usage return contracts.Usage{}, err } - sector, err := sh.storage.Read(root) + sector, err := sh.sectors.Read(root) if err != nil { s.t.WriteResponseErr(ErrHostInternalError) return contracts.Usage{}, fmt.Errorf("failed to read sector %v: %w", root, err) @@ -686,7 +687,7 @@ func (sh *SessionHandler) rpcWrite(s *session, log *zap.Logger) (contracts.Usage s.t.WriteResponseErr(err) return contracts.Usage{}, err } - release, err := sh.storage.Write(root, sector) + release, err := sh.sectors.Write(root, sector) if err != nil { err := fmt.Errorf("append action: failed to write sector: %w", err) s.t.WriteResponseErr(err) @@ -733,7 +734,7 @@ func (sh *SessionHandler) rpcWrite(s *session, log *zap.Logger) (contracts.Usage } // sync the storage manager - if err := sh.storage.Sync(); err != nil { + if err := sh.sectors.Sync(); err != nil { s.t.WriteResponseErr(ErrHostInternalError) return contracts.Usage{}, fmt.Errorf("failed to sync storage manager: %w", err) } @@ -770,7 +771,7 @@ func (sh *SessionHandler) rpcRead(s *session, log *zap.Logger) (contracts.Usage, } // get the host's current settings - settings, err := sh.Settings() + settings, err := sh.settings.RHP2Settings() if err != nil { s.t.WriteResponseErr(ErrHostInternalError) return contracts.Usage{}, fmt.Errorf("failed to get host settings: %w", err) @@ -859,7 +860,7 @@ func (sh *SessionHandler) rpcRead(s *session, log *zap.Logger) (contracts.Usage, // enter response loop for i, sec := range req.Sections { - sector, err := sh.storage.Read(sec.MerkleRoot) + sector, err := sh.sectors.Read(sec.MerkleRoot) if err != nil { err := fmt.Errorf("failed to get sector: %w", err) s.t.WriteResponseErr(err) diff --git a/rhp/v2/rpc_test.go b/rhp/v2/rpc_test.go index 10f01932..3c67c4ec 100644 --- a/rhp/v2/rpc_test.go +++ b/rhp/v2/rpc_test.go @@ -59,7 +59,7 @@ func TestSettings(t *testing.T) { } defer l.Close() - sh, err := rhp2.NewSessionHandler(l, hostKey, "localhost:9983", node.Chain, node.Syncer, node.Wallet, node.Contracts, node.Settings, node.Volumes, rhp2.WithLog(log)) + sh, err := rhp2.NewSessionHandler(l, hostKey, node.Chain, node.Syncer, node.Wallet, node.Contracts, node.Settings, node.Volumes, rhp2.WithLog(log)) if err != nil { t.Fatal(err) } @@ -74,7 +74,7 @@ func TestSettings(t *testing.T) { t.Fatal(err) } - expected, err := sh.Settings() + expected, err := node.Settings.RHP2Settings() if err != nil { t.Fatal(err) } @@ -115,7 +115,7 @@ func TestUploadDownload(t *testing.T) { } defer l.Close() - sh, err := rhp2.NewSessionHandler(l, hostKey, "localhost:9983", node.Chain, node.Syncer, node.Wallet, node.Contracts, node.Settings, node.Volumes, rhp2.WithLog(log)) + sh, err := rhp2.NewSessionHandler(l, hostKey, node.Chain, node.Syncer, node.Wallet, node.Contracts, node.Settings, node.Volumes, rhp2.WithLog(log)) if err != nil { t.Fatal(err) } @@ -221,7 +221,7 @@ func TestRenew(t *testing.T) { } defer l.Close() - sh, err := rhp2.NewSessionHandler(l, hostKey, "localhost:9983", node.Chain, node.Syncer, node.Wallet, node.Contracts, node.Settings, node.Volumes, rhp2.WithLog(log)) + sh, err := rhp2.NewSessionHandler(l, hostKey, node.Chain, node.Syncer, node.Wallet, node.Contracts, node.Settings, node.Volumes, rhp2.WithLog(log)) if err != nil { t.Fatal(err) } @@ -429,7 +429,7 @@ func TestRPCV2(t *testing.T) { } defer l.Close() - sh, err := rhp2.NewSessionHandler(l, hostKey, "localhost:9983", node.Chain, node.Syncer, node.Wallet, node.Contracts, node.Settings, node.Volumes, rhp2.WithLog(log)) + sh, err := rhp2.NewSessionHandler(l, hostKey, node.Chain, node.Syncer, node.Wallet, node.Contracts, node.Settings, node.Volumes, rhp2.WithLog(log)) if err != nil { t.Fatal(err) } diff --git a/rhp/v3/payments.go b/rhp/v3/payments.go index 287b30eb..f791ca0c 100644 --- a/rhp/v3/payments.go +++ b/rhp/v3/payments.go @@ -59,7 +59,7 @@ func (sh *SessionHandler) processContractPayment(s *rhp3.Stream, _ uint64) (rhp3 return rhp3.ZeroAccount, types.ZeroCurrency, ErrInvalidRenterSignature } - settings := sh.settings.Settings() + settings, err := sh.settings.RHP2Settings() hostSig := sh.privateKey.SignHash(sigHash) fundReq := accounts.FundAccountWithContract{ Account: req.RefundAccount, @@ -69,7 +69,7 @@ func (sh *SessionHandler) processContractPayment(s *rhp3.Stream, _ uint64) (rhp3 RenterSignature: req.Signature, }, Amount: fundAmount, - Expiration: time.Now().Add(settings.AccountExpiry), + Expiration: time.Now().Add(settings.EphemeralAccountExpiry), } // credit the account with the deposit _, err = sh.accounts.Credit(fundReq, true) @@ -199,7 +199,11 @@ func (sh *SessionHandler) processFundAccountPayment(pt rhp3.HostPriceTable, s *r return types.ZeroCurrency, types.ZeroCurrency, ErrInvalidRenterSignature } - settings := sh.settings.Settings() + settings, err := sh.settings.RHP2Settings() + if err != nil { + s.WriteResponseErr(ErrHostInternalError) + return types.ZeroCurrency, types.ZeroCurrency, fmt.Errorf("failed to get host settings: %w", err) + } // credit the account with the deposit hostSig := sh.privateKey.SignHash(sigHash) fundReq := accounts.FundAccountWithContract{ @@ -211,7 +215,7 @@ func (sh *SessionHandler) processFundAccountPayment(pt rhp3.HostPriceTable, s *r }, Cost: pt.FundAccountCost, Amount: totalAmount.Sub(pt.FundAccountCost), - Expiration: time.Now().Add(settings.AccountExpiry), + Expiration: time.Now().Add(settings.EphemeralAccountExpiry), } // credit the account with the deposit balance, err = sh.accounts.Credit(fundReq, false) diff --git a/rhp/v3/pricetable.go b/rhp/v3/pricetable.go index 44f406e8..134d98b4 100644 --- a/rhp/v3/pricetable.go +++ b/rhp/v3/pricetable.go @@ -8,8 +8,6 @@ import ( "time" rhp3 "go.sia.tech/core/rhp/v3" - "go.sia.tech/core/types" - "lukechampine.com/frand" ) type ( @@ -104,73 +102,6 @@ func (pm *priceTableManager) Register(pt rhp3.HostPriceTable) { } } -// PriceTable returns the session handler's current price table. -func (sh *SessionHandler) PriceTable() (rhp3.HostPriceTable, error) { - settings := sh.settings.Settings() - count, limit, err := sh.registry.Entries() - if err != nil { - return rhp3.HostPriceTable{}, fmt.Errorf("failed to get registry entries: %w", err) - } - - fee := sh.chain.RecommendedFee() - currentHeight := sh.chain.TipState().Index.Height - oneHasting := types.NewCurrency64(1) - return rhp3.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: limit - count, - RegistryEntriesTotal: limit, - - // Subscription related fields. - SubscriptionMemoryCost: oneHasting, - SubscriptionNotificationCost: oneHasting, - - // TxnFee related fields. - TxnFeeMinRecommended: fee.Div64(3), - TxnFeeMaxRecommended: fee, - }, nil -} - // readPriceTable reads the price table ID from the stream and returns an error // if the price table is invalid or expired. func (sh *SessionHandler) readPriceTable(s *rhp3.Stream) (rhp3.HostPriceTable, error) { diff --git a/rhp/v3/rhp.go b/rhp/v3/rhp.go index bb775ac6..e8e998de 100644 --- a/rhp/v3/rhp.go +++ b/rhp/v3/rhp.go @@ -13,7 +13,6 @@ import ( "go.sia.tech/core/types" "go.sia.tech/hostd/host/accounts" "go.sia.tech/hostd/host/contracts" - "go.sia.tech/hostd/host/settings" "go.sia.tech/hostd/host/storage" "go.sia.tech/hostd/internal/threadgroup" "go.sia.tech/hostd/rhp" @@ -52,8 +51,6 @@ type ( // A StorageManager manages the storage of sectors on disk. StorageManager interface { - Usage() (used, total uint64, _ error) - // LockSector locks the sector with the given root. If the sector does not // exist, an error is returned. Release must be called when the sector is no // longer needed. @@ -106,7 +103,9 @@ type ( // A SettingsReporter reports the host's current configuration. SettingsReporter interface { - Settings() settings.Settings + AcceptingContracts() bool + RHP2Settings() (rhp2.HostSettings, error) + RHP3PriceTable() (rhp3.HostPriceTable, error) BandwidthLimiters() (ingress, egress *rate.Limiter) } diff --git a/rhp/v3/rpc.go b/rhp/v3/rpc.go index f65b5ea1..ed200b5b 100644 --- a/rhp/v3/rpc.go +++ b/rhp/v3/rpc.go @@ -52,7 +52,7 @@ var ( // handleRPCPriceTable sends the host's price table to the renter. func (sh *SessionHandler) handleRPCPriceTable(s *rhp3.Stream, log *zap.Logger) (contracts.Usage, error) { - pt, err := sh.PriceTable() + pt, err := sh.settings.RHP3PriceTable() if err != nil { s.WriteResponseErr(ErrHostInternalError) return contracts.Usage{}, fmt.Errorf("failed to get price table: %w", err) @@ -255,14 +255,14 @@ func (sh *SessionHandler) handleRPCRenew(s *rhp3.Stream, log *zap.Logger) (contr } s.SetDeadline(time.Now().Add(2 * time.Minute)) - if !sh.settings.Settings().AcceptingContracts { + if !sh.settings.AcceptingContracts() { s.WriteResponseErr(ErrNotAcceptingContracts) return contracts.Usage{}, ErrNotAcceptingContracts } pt, err := sh.readPriceTable(s) if errors.Is(err, ErrNoPriceTable) { // no price table, send the renter a default one - pt, err = sh.PriceTable() + pt, err = sh.settings.RHP3PriceTable() if err != nil { s.WriteResponseErr(ErrHostInternalError) return contracts.Usage{}, fmt.Errorf("failed to get price table: %w", err) diff --git a/rhp/v3/rpc_test.go b/rhp/v3/rpc_test.go index ae4ef18e..855cd6ec 100644 --- a/rhp/v3/rpc_test.go +++ b/rhp/v3/rpc_test.go @@ -105,7 +105,7 @@ func setupRHP3Host(t *testing.T, node *testutil.HostNode, hostKey types.PrivateK t.Fatal(err) } - sh2, err := rhp2.NewSessionHandler(rhp2Listener, hostKey, rhp3Listener.Addr().String(), node.Chain, node.Syncer, node.Wallet, node.Contracts, node.Settings, node.Volumes, rhp2.WithLog(log.Named("rhp2"))) + sh2, err := rhp2.NewSessionHandler(rhp2Listener, hostKey, node.Chain, node.Syncer, node.Wallet, node.Contracts, node.Settings, node.Volumes, rhp2.WithLog(log.Named("rhp2"))) if err != nil { t.Fatal(err) } @@ -141,7 +141,7 @@ func TestPriceTable(t *testing.T) { } defer session.Close() - pt, err := sh3.PriceTable() + pt, err := node.Settings.RHP3PriceTable() if err != nil { t.Fatal(err) } From cf191e25014c65c63e0ab5a9855a85aa45f1fc0e Mon Sep 17 00:00:00 2001 From: Nate Date: Mon, 18 Nov 2024 14:24:42 -0800 Subject: [PATCH 2/2] add changeset --- ...ngs_into_the_config_manager_to_be_consistent_with_rhp4.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/move_rhp2_and_rhp3_settings_into_the_config_manager_to_be_consistent_with_rhp4.md diff --git a/.changeset/move_rhp2_and_rhp3_settings_into_the_config_manager_to_be_consistent_with_rhp4.md b/.changeset/move_rhp2_and_rhp3_settings_into_the_config_manager_to_be_consistent_with_rhp4.md new file mode 100644 index 00000000..2a6b4757 --- /dev/null +++ b/.changeset/move_rhp2_and_rhp3_settings_into_the_config_manager_to_be_consistent_with_rhp4.md @@ -0,0 +1,5 @@ +--- +default: patch +--- + +# Move RHP2 and RHP3 settings into the config manager to be consistent with RHP4