// maxSectors is the estimated maximum number of sectors that the allowance // can support. func maxSectors(a modules.Allowance, hdb hostDB) (uint64, error) { if a.Hosts == 0 || a.Period == 0 { return 0, errors.New("invalid allowance") } // Sample at least 10 hosts. nRandomHosts := int(a.Hosts) if nRandomHosts < 10 { nRandomHosts = 10 } hosts := hdb.RandomHosts(nRandomHosts, nil) if len(hosts) < int(a.Hosts) { return 0, errors.New("not enough hosts") } // Calculate cost of storing 1 sector per host for the allowance period. var sum types.Currency for _, h := range hosts { sum = sum.Add(h.StoragePrice) } averagePrice := sum.Div64(uint64(len(hosts))) costPerSector := averagePrice.Mul64(a.Hosts).Mul64(modules.SectorSize).Mul64(uint64(a.Period)) // Divide total funds by cost per sector. numSectors, err := a.Funds.Div(costPerSector).Uint64() if err != nil { // if there was an overflow, something is definitely wrong return 0, errors.New("allowance can fund suspiciously large number of sectors") } return numSectors, nil }
// CalculateFee returns the fee-per-byte of a transaction set. func CalculateFee(ts []types.Transaction) types.Currency { var sum types.Currency for _, t := range ts { for _, fee := range t.MinerFees { sum = sum.Add(fee) } } size := len(encoding.Marshal(ts)) return sum.Div64(uint64(size)) }
// AverageContractPrice returns the average price of a host. func (hdb *HostDB) AverageContractPrice() types.Currency { // maybe a more sophisticated way of doing this var totalPrice types.Currency sampleSize := 18 hosts := hdb.RandomHosts(sampleSize, nil) if len(hosts) == 0 { return totalPrice } for _, host := range hosts { totalPrice = totalPrice.Add(host.ContractPrice) } return totalPrice.Div64(uint64(len(hosts))) }
// hostcmd is the handler for the command `siac host`. // Prints info about the host and its storage folders. func hostcmd() { hg := new(api.HostGET) err := getAPI("/host", hg) if err != nil { die("Could not fetch host settings:", err) } sg := new(api.StorageGET) err = getAPI("/host/storage", sg) if err != nil { die("Could not fetch storage info:", err) } // Determine the competitive price string. ah := new(api.ActiveHosts) var competitivePrice string err = getAPI("/hostdb/active?numhosts=24", ah) if err != nil || len(ah.Hosts) == 0 { competitivePrice = "Unavailable" } else { var sum types.Currency for _, host := range ah.Hosts { sum = sum.Add(host.StoragePrice) } // Divide by the number of hosts to get the average price, and then // trim 5% to present what would be a competitive edge. competitivePrice = currencyUnits(sum.Div64(uint64(len(ah.Hosts))).MulFloat(0.95).Mul(modules.BlockBytesPerMonthTerabyte)) } es := hg.ExternalSettings fm := hg.FinancialMetrics is := hg.InternalSettings nm := hg.NetworkMetrics // calculate total storage available and remaining var totalstorage, storageremaining uint64 for _, folder := range sg.Folders { totalstorage += folder.Capacity storageremaining += folder.CapacityRemaining } // convert price from bytes/block to TB/Month price := currencyUnits(is.MinStoragePrice.Mul(modules.BlockBytesPerMonthTerabyte)) // calculate total revenue totalRevenue := fm.ContractCompensation. Add(fm.StorageRevenue). Add(fm.DownloadBandwidthRevenue). Add(fm.UploadBandwidthRevenue) totalPotentialRevenue := fm.PotentialContractCompensation. Add(fm.PotentialStorageRevenue). Add(fm.PotentialDownloadBandwidthRevenue). Add(fm.PotentialUploadBandwidthRevenue) // determine the display method for the net address. netaddr := es.NetAddress if is.NetAddress == "" { netaddr += " (automatically determined)" } else { netaddr += " (manually specified)" } if hostVerbose { // describe net address fmt.Printf(`General Info: Estimated Competitive Price: %v Host Internal Settings: acceptingcontracts: %v maxduration: %v Weeks maxdownloadbatchsize: %v maxrevisebatchsize: %v netaddress: %v windowsize: %v Hours collateral: %v / TB / Month collateralbudget: %v maxcollateral: %v Per Contract mincontractprice: %v mindownloadbandwidthprice: %v / TB minstorageprice: %v / TB / Month minuploadbandwidthprice: %v / TB Host Financials: Contract Count: %v Transaction Fee Compensation: %v Potential Fee Compensation: %v Transaction Fee Expenses: %v Storage Revenue: %v Potential Storage Revenue: %v Locked Collateral: %v Risked Collateral: %v Lost Collateral: %v Download Revenue: %v Potential Download Revenue: %v Upload Revenue : %v Potential Upload Revenue: %v RPC Stats: Error Calls: %v Unrecognized Calls: %v Download Calls: %v Renew Calls: %v Revise Calls: %v Settings Calls: %v FormContract Calls: %v `, competitivePrice, yesNo(is.AcceptingContracts), periodUnits(is.MaxDuration), filesizeUnits(int64(is.MaxDownloadBatchSize)), filesizeUnits(int64(is.MaxReviseBatchSize)), netaddr, is.WindowSize/6, currencyUnits(is.Collateral.Mul(modules.BlockBytesPerMonthTerabyte)), currencyUnits(is.CollateralBudget), currencyUnits(is.MaxCollateral), currencyUnits(is.MinContractPrice), currencyUnits(is.MinDownloadBandwidthPrice.Mul(modules.BytesPerTerabyte)), currencyUnits(is.MinStoragePrice.Mul(modules.BlockBytesPerMonthTerabyte)), currencyUnits(is.MinUploadBandwidthPrice.Mul(modules.BytesPerTerabyte)), fm.ContractCount, currencyUnits(fm.ContractCompensation), currencyUnits(fm.PotentialContractCompensation), currencyUnits(fm.TransactionFeeExpenses), currencyUnits(fm.StorageRevenue), currencyUnits(fm.PotentialStorageRevenue), currencyUnits(fm.LockedStorageCollateral), currencyUnits(fm.RiskedStorageCollateral), currencyUnits(fm.LostStorageCollateral), currencyUnits(fm.DownloadBandwidthRevenue), currencyUnits(fm.PotentialDownloadBandwidthRevenue), currencyUnits(fm.UploadBandwidthRevenue), currencyUnits(fm.PotentialUploadBandwidthRevenue), nm.ErrorCalls, nm.UnrecognizedCalls, nm.DownloadCalls, nm.RenewCalls, nm.ReviseCalls, nm.SettingsCalls, nm.FormContractCalls) } else { fmt.Printf(`Host info: Estimated Competitive Price: %v Storage: %v (%v used) Price: %v / TB / Month Max Duration: %v Weeks Accepting Contracts: %v Anticipated Revenue: %v Locked Collateral: %v Revenue: %v `, competitivePrice, filesizeUnits(int64(totalstorage)), filesizeUnits(int64(totalstorage-storageremaining)), price, periodUnits(is.MaxDuration), yesNo(is.AcceptingContracts), currencyUnits(totalPotentialRevenue), currencyUnits(fm.LockedStorageCollateral), currencyUnits(totalRevenue)) } fmt.Println("\nStorage Folders:") // display storage folder info if len(sg.Folders) == 0 { fmt.Println("No storage folders configured") return } w := tabwriter.NewWriter(os.Stdout, 0, 0, 4, ' ', 0) fmt.Fprintf(w, "\tUsed\tCapacity\t%% Used\tPath\n") for _, folder := range sg.Folders { curSize := int64(folder.Capacity - folder.CapacityRemaining) pctUsed := 100 * (float64(curSize) / float64(folder.Capacity)) fmt.Fprintf(w, "\t%s\t%s\t%.2f\t%s\n", filesizeUnits(curSize), filesizeUnits(int64(folder.Capacity)), pctUsed, folder.Path) } w.Flush() }