diff --git a/.changeset/quick-forks-try.md b/.changeset/quick-forks-try.md new file mode 100644 index 000000000..6cc279262 --- /dev/null +++ b/.changeset/quick-forks-try.md @@ -0,0 +1,6 @@ +--- +'hostd': minor +'walletd': minor +--- + +App preferences no longer list unused GPU setting. diff --git a/.changeset/sixty-suns-invite.md b/.changeset/sixty-suns-invite.md new file mode 100644 index 000000000..384f89119 --- /dev/null +++ b/.changeset/sixty-suns-invite.md @@ -0,0 +1,5 @@ +--- +'renterd': minor +--- + +The configuration now includes a setting for a migration surcharge multiplier which allows you to set a factor for increasing the max download price when trying to repair critically low health sectors. diff --git a/.changeset/soft-yaks-rush.md b/.changeset/soft-yaks-rush.md new file mode 100644 index 000000000..60340d96a --- /dev/null +++ b/.changeset/soft-yaks-rush.md @@ -0,0 +1,5 @@ +--- +'renterd': minor +--- + +The contracts table now includes a column for state that shows: pending, active, complete, or failed. diff --git a/apps/renterd/contexts/config/fields.tsx b/apps/renterd/contexts/config/fields.tsx index 33ec34c07..c2a9f1a4c 100644 --- a/apps/renterd/contexts/config/fields.tsx +++ b/apps/renterd/contexts/config/fields.tsx @@ -567,6 +567,32 @@ export function getFields({ } : {}, }, + migrationSurchargeMultiplier: { + category: 'gouging', + type: 'number', + title: 'Migration surcharge multiplier', + units: '* download price', + placeholder: '10', + decimalsLimit: 1, + description: ( + <> + Factor that gets applied on the max download price when trying to + download migration-critical sectors from a host that is price gouging. + For example, when migrating a low-health file, if the download is + failing but would potentially succeed with looser gouging settings, we + apply the migration surcharge multiplier to overpay on every sector + download if it means saving the file/migration. + + ), + suggestion: new BigNumber(10), + suggestionTip: 'The default multiplier is 10x the download price.', + hidden: !showAdvanced, + validation: showAdvanced + ? { + required: 'required', + } + : {}, + }, // Redundancy minShards: { diff --git a/apps/renterd/contexts/config/transform.spec.ts b/apps/renterd/contexts/config/transform.spec.ts index 184215dc7..9271c58ba 100644 --- a/apps/renterd/contexts/config/transform.spec.ts +++ b/apps/renterd/contexts/config/transform.spec.ts @@ -55,6 +55,7 @@ describe('tansforms', () => { minMaxCollateral: '10000000000000000000000000', minMaxEphemeralAccountBalance: '1000000000000000000000000', minPriceTableValidity: 300000000000, + migrationSurchargeMultiplier: 10, }, { minShards: 10, @@ -90,6 +91,7 @@ describe('tansforms', () => { minMaxCollateral: new BigNumber('10'), minMaxEphemeralAccountBalance: new BigNumber('1'), minPriceTableValidityMinutes: new BigNumber(5), + migrationSurchargeMultiplier: new BigNumber(10), minShards: new BigNumber(10), totalShards: new BigNumber(30), includeRedundancyMaxStoragePrice: false, @@ -134,6 +136,7 @@ describe('tansforms', () => { minMaxCollateral: '10000000000000000000000000', minMaxEphemeralAccountBalance: '1000000000000000000000000', minPriceTableValidity: 300000000000, + migrationSurchargeMultiplier: 10, }, { minShards: 10, @@ -169,6 +172,7 @@ describe('tansforms', () => { minMaxCollateral: new BigNumber('10'), minMaxEphemeralAccountBalance: new BigNumber('1'), minPriceTableValidityMinutes: new BigNumber(5), + migrationSurchargeMultiplier: new BigNumber(10), minShards: new BigNumber(10), totalShards: new BigNumber(30), includeRedundancyMaxStoragePrice: true, @@ -327,6 +331,7 @@ describe('tansforms', () => { minPriceTableValidityMinutes: new BigNumber(5), minShards: new BigNumber(10), totalShards: new BigNumber(30), + migrationSurchargeMultiplier: new BigNumber(10), includeRedundancyMaxStoragePrice: false, includeRedundancyMaxUploadPrice: false, }, @@ -348,6 +353,7 @@ describe('tansforms', () => { minMaxCollateral: '10000000000000000000000000', minMaxEphemeralAccountBalance: '1000000000000000000000000', minPriceTableValidity: 300000000000, + migrationSurchargeMultiplier: 10, }) }) @@ -379,6 +385,7 @@ describe('tansforms', () => { minMaxCollateral: new BigNumber('10'), minMaxEphemeralAccountBalance: new BigNumber('1'), minPriceTableValidityMinutes: new BigNumber(5), + migrationSurchargeMultiplier: new BigNumber(10), minShards: new BigNumber(10), totalShards: new BigNumber(30), includeRedundancyMaxStoragePrice: true, @@ -402,6 +409,7 @@ describe('tansforms', () => { minMaxCollateral: '10000000000000000000000000', minMaxEphemeralAccountBalance: '1000000000000000000000000', minPriceTableValidity: 300000000000, + migrationSurchargeMultiplier: 10, }) }) @@ -551,6 +559,7 @@ function buildAllResponses() { minMaxCollateral: '10000000000000000000000000', minMaxEphemeralAccountBalance: '1000000000000000000000000', minPriceTableValidity: 300000000000, + migrationSurchargeMultiplier: 10, }, redundancy: { minShards: 10, diff --git a/apps/renterd/contexts/config/transform.ts b/apps/renterd/contexts/config/transform.ts index 25f7ab56d..4aeed90be 100644 --- a/apps/renterd/contexts/config/transform.ts +++ b/apps/renterd/contexts/config/transform.ts @@ -163,6 +163,8 @@ export function transformUpGouging( minMaxEphemeralAccountBalance: toHastings( values.minMaxEphemeralAccountBalance ).toString(), + migrationSurchargeMultiplier: + values.migrationSurchargeMultiplier.toNumber(), } } @@ -323,6 +325,7 @@ export function transformDownGouging( g.minMaxEphemeralAccountBalance, scDecimalPlaces ), + migrationSurchargeMultiplier: new BigNumber(g.migrationSurchargeMultiplier), } } diff --git a/apps/renterd/contexts/config/types.ts b/apps/renterd/contexts/config/types.ts index 88c886d51..3e00acbfc 100644 --- a/apps/renterd/contexts/config/types.ts +++ b/apps/renterd/contexts/config/types.ts @@ -45,6 +45,7 @@ export const defaultGouging = { minPriceTableValidityMinutes: undefined as BigNumber | undefined, minAccountExpiryDays: undefined as BigNumber | undefined, minMaxEphemeralAccountBalance: undefined as BigNumber | undefined, + migrationSurchargeMultiplier: undefined as BigNumber | undefined, } export const defaultRedundancy = { diff --git a/apps/renterd/contexts/contracts/columns.tsx b/apps/renterd/contexts/contracts/columns.tsx index aa2b11b6c..8d11b51d9 100644 --- a/apps/renterd/contexts/contracts/columns.tsx +++ b/apps/renterd/contexts/contracts/columns.tsx @@ -7,11 +7,14 @@ import { stripPrefix, Tooltip, ValueNum, + Badge, + Separator, } from '@siafoundation/design-system' import { ArrowUpLeft16 } from '@siafoundation/react-icons' import { humanBytes, humanDate } from '@siafoundation/sia-js' import { ContractData, TableColumnId } from './types' import { ContractContextMenu } from '../../components/Contracts/ContractContextMenu' +import { ContractState } from '@siafoundation/react-renterd' type Context = { currentHeight: number @@ -95,6 +98,59 @@ export const columns: ContractsTableColumn[] = [ return }, }, + { + id: 'state', + label: 'state', + category: 'general', + render: ({ data: { state } }) => { + return ( + +
+ + pending + + + Contract has been added. + +
+ +
+ + active + + + Contract has appeared on chain. + +
+ +
+ + complete + + + Storage proof has appeared on chain. + +
+ +
+ + failed + + + Storage proof was not submitted before the end of proof + window. + +
+ + } + > + {state} +
+ ) + }, + }, { id: 'timeline', label: 'timeline', @@ -207,3 +263,18 @@ export const columns: ContractsTableColumn[] = [ ), }, ] + +function getContractStateColor(state: ContractState) { + if (state === 'active') { + return 'amber' + } + if (state === 'failed') { + return 'red' + } + if (state === 'pending') { + return 'amber' + } + if (state === 'complete') { + return 'green' + } +} diff --git a/apps/renterd/contexts/contracts/index.tsx b/apps/renterd/contexts/contracts/index.tsx index 428a39198..1eab64ee9 100644 --- a/apps/renterd/contexts/contracts/index.tsx +++ b/apps/renterd/contexts/contracts/index.tsx @@ -57,6 +57,7 @@ function useContractsMain() { return { id: c.id, contractId: c.id, + state: c.state, hostIp: c.hostIP, hostKey: c.hostKey, location: geoHosts.find((h) => h.public_key === c.hostKey)?.location, diff --git a/apps/renterd/contexts/contracts/types.ts b/apps/renterd/contexts/contracts/types.ts index 653fd80fb..9d604cdc0 100644 --- a/apps/renterd/contexts/contracts/types.ts +++ b/apps/renterd/contexts/contracts/types.ts @@ -1,9 +1,11 @@ +import { ContractState } from '@siafoundation/react-renterd' import BigNumber from 'bignumber.js' export type ContractData = { id: string hostIp: string hostKey: string + state: ContractState location?: [number, number] isRenewed: boolean renewedFrom: string @@ -28,6 +30,7 @@ export type TableColumnId = | 'contractId' | 'hostIp' | 'hostKey' + | 'state' | 'timeline' | 'startTime' | 'endTime' @@ -41,6 +44,7 @@ export const columnsDefaultVisible: TableColumnId[] = [ 'contractId', 'hostIp', 'hostKey', + 'state', 'timeline', 'size', 'totalCost', @@ -53,6 +57,7 @@ export type SortField = | 'contractId' | 'hostIp' | 'hostKey' + | 'state' | 'timeline' | 'startTime' | 'endTime' @@ -84,6 +89,11 @@ export const sortOptions: { label: 'host public key', category: 'general', }, + { + id: 'state', + label: 'state', + category: 'general', + }, { id: 'timeline', label: 'timeline', diff --git a/apps/renterd/contexts/dialog.tsx b/apps/renterd/contexts/dialog.tsx index c2c482e5e..e954fe524 100644 --- a/apps/renterd/contexts/dialog.tsx +++ b/apps/renterd/contexts/dialog.tsx @@ -137,6 +137,7 @@ export function Dialogs() { void securityEl?: React.ReactNode + showGpuSetting?: boolean } -export function SettingsDialog({ open, onOpenChange, securityEl }: Props) { +export function SettingsDialog({ + open, + onOpenChange, + securityEl, + showGpuSetting, +}: Props) { const { settings, setSettings, gpu } = useAppSettings() return ( @@ -96,30 +102,32 @@ export function SettingsDialog({ open, onOpenChange, securityEl }: Props) { - -
-
- - - - - GPU - - + {showGpuSetting && ( + +
+
+ + + + + GPU + + +
+ + Enable features that require a GPU.{' '} + {gpu.canGpuRender + ? '' + : 'This device does not support GPU rendering.'} +
- - Enable features that require a GPU.{' '} - {gpu.canGpuRender - ? '' - : 'This device does not support GPU rendering.'} - -
- + + )}
diff --git a/libs/react-renterd/src/siaTypes.ts b/libs/react-renterd/src/siaTypes.ts index 06cda247f..9efe939fa 100644 --- a/libs/react-renterd/src/siaTypes.ts +++ b/libs/react-renterd/src/siaTypes.ts @@ -191,6 +191,7 @@ export type GougingSettings = { minPriceTableValidity: number minAccountExpiry: number minMaxEphemeralAccountBalance: string + migrationSurchargeMultiplier: number } export type UploadPackingSettings = { @@ -208,6 +209,8 @@ export interface ContractSpending { fundAccount: Currency } +export type ContractState = 'pending' | 'active' | 'complete' | 'failed' + export interface Contract { id: string hostIP: string @@ -222,6 +225,7 @@ export interface Contract { spending: ContractSpending totalCost: Currency size: number + state: ContractState } export interface Block {