diff --git a/htdocs/index.html b/htdocs/index.html index bc99d50..8ccc022 100644 --- a/htdocs/index.html +++ b/htdocs/index.html @@ -161,7 +161,7 @@

Your storage allowance automatically refills every 6 weeks. Your computer must be online with your wallet unlocked to complete the refill. If Sia fails to refill the allowance by the end of the lock-in period, your data may be lost.

*contract fees are non-refundable. They will be subtracted from the allowance that you set.

Allocated Funds

-

+


Number of Hosts



Contract Period

diff --git a/htdocs/js/index.js b/htdocs/js/index.js index a22c616..3c66a7a 100644 --- a/htdocs/js/index.js +++ b/htdocs/js/index.js @@ -175,6 +175,9 @@ window.appActions.setRenterSettings(allowance, cb); } + function _calculateEstimatedStorage(funds) { + return window.appActions.calculateEstimatedStorage(funds) + } return { createWallet: _createWallet, mountDrive: _mountDrive, @@ -183,7 +186,8 @@ unlockWallet: _unlockWallet, unmountDrive: _unmountDrive, shutdown: _shutdown, - setRenterSettings: _setRenterSettings + setRenterSettings: _setRenterSettings, + calculateEstimatedStorage: _calculateEstimatedStorage }; })(); @@ -269,8 +273,15 @@ function handleRenterEditSettings() { setMainWindow('renter_settings_window'); + const estStorage = document.getElementById('ID_RenterCalcStorage'); + const funds = document.getElementById('ID_RenterSetFunds'); + funds.oninput = () => { + estStorage.innerText = AppActions.calculateEstimatedStorage(funds.value); + }; + const defaultsButton = document.getElementById('ID_RenterSettingsDefaults'); defaultsButton.onclick = ()=> { + funds.oninput = null; const settings = UiState.defaultRenterSettings(); if (getValue('ID_RenterSetFunds') === '0') { setValue('ID_RenterSetFunds', settings.Funds); @@ -282,6 +293,7 @@ const cancelButton = document.getElementById('ID_RenterSettingsCancel'); cancelButton.onclick = ()=> { + funds.oninput = null; saveButton.onclick = null; cancelButton.onclick = null; defaultsButton.onclick = null; @@ -290,6 +302,7 @@ const saveButton = document.getElementById('ID_RenterSettingsOK'); saveButton.onclick = ()=> { + funds.oninput = null; saveButton.onclick = null; cancelButton.onclick = null; defaultsButton.onclick = null; diff --git a/include/siadrive_api/siaapi.h b/include/siadrive_api/siaapi.h index b56387c..ea84bc5 100644 --- a/include/siadrive_api/siaapi.h +++ b/include/siadrive_api/siaapi.h @@ -176,6 +176,7 @@ public: void Refresh(const CSiaCurl& siaCurl, CSiaDriveConfig* siaDriveConfig); public: + CSiaError<_SiaApiErrorCode> CalculateEstimatedStorage(const SiaCurrency& funds, SiaCurrency& resultGb) const; CSiaError<_SiaApiErrorCode> DownloadFile(const SString& siaPath, const SString& location) const; CSiaError<_SiaApiErrorCode> FileExists(const SString& siaPath, bool& exists) const; _SiaRenterAllowance GetAllowance() const; @@ -205,6 +206,52 @@ public: void Refresh(const CSiaCurl& siaCurl, CSiaDriveConfig* siaDriveConfig); }; + class SIADRIVE_EXPORTABLE _CSiaHost : + public virtual CSiaBase + { + friend CSiaApi; + + private: + explicit _CSiaHost(const CSiaCurl& siaCurl, CSiaDriveConfig* siaDriveConfig, const json& hostJson); + + public: + virtual ~_CSiaHost(); + + //Properties + Property(bool, AcceptingContracts, public, private) + Property(std::uint64_t, MaxDownloadBatchSize, public, private) + Property(std::uint64_t, MaxDuration, public, private) + Property(std::uint64_t, MaxReviseBatchSize, public, private) + Property(SString, NetAddress, public, private) + Property(std::uint64_t, RemainingStorage, public, private) + Property(std::uint64_t, SectorSize, public, private) + Property(std::uint64_t, TotalStorage, public, private) + Property(SString, UnlockHash, public, private) + Property(std::uint64_t, WindowSize, public, private) + Property(std::pair, PublicKey, public, private) + }; + + class SIADRIVE_EXPORTABLE _CSiaHostDb : + public virtual CSiaBase + { + friend CSiaApi; + + private: + explicit _CSiaHostDb(const CSiaCurl& siaCurl, CSiaDriveConfig* siaDriveConfig); + + public: + virtual ~_CSiaHostDb(); + + private: + std::shared_ptr>> _activeHosts; + + private: + void Refresh(const CSiaCurl& siaCurl, CSiaDriveConfig* siaDriveConfig); + + public: + std::shared_ptr>> GetActiveHosts() const; + }; + public: explicit CSiaApi(const SiaHostConfig& hostConfig, CSiaDriveConfig* siaDriveConfig); @@ -217,7 +264,8 @@ private: CSiaDriveConfig* _siaDriveConfig; std::shared_ptr<_CSiaWallet> _wallet; std::shared_ptr<_CSiaRenter> _renter; - std::shared_ptr<_CSiaConsensus> _consensus; + std::shared_ptr<_CSiaConsensus> _consensus; + std::shared_ptr<_CSiaHostDb> _hostDb; std::unique_ptr _refreshThread; private: @@ -229,7 +277,8 @@ public: public: std::shared_ptr<_CSiaWallet> GetWallet() const; std::shared_ptr<_CSiaRenter> GetRenter() const; - std::shared_ptr<_CSiaConsensus> GetConsensus() const; + std::shared_ptr<_CSiaConsensus> GetConsensus() const; + std::shared_ptr<_CSiaHostDb> GetHostDb() const; SString GetServerVersion() const; SiaHostConfig GetHostConfig() const; }; @@ -241,9 +290,15 @@ typedef CSiaApi::_CSiaWallet CSiaWallet; typedef CSiaApi::_CSiaRenter CSiaRenter; typedef CSiaRenter::_SiaRenterAllowance SiaRenterAllowance; typedef CSiaApi::_CSiaConsensus CSiaConsensus; +typedef CSiaApi::_CSiaHostDb CSiaHostDb; +typedef CSiaApi::_CSiaHost CSiaHost; +typedef std::shared_ptr CSiaHostDbPtr; typedef std::shared_ptr CSiaWalletPtr; typedef std::shared_ptr CSiaRenterPtr; typedef std::shared_ptr CSiaConsensusPtr; +typedef std::shared_ptr CSiaHostPtr; +typedef std::vector CSiaHostCollection; +typedef std::shared_ptr CSiaHostCollectionPtr; typedef CSiaApi::_CSiaFile CSiaFile; typedef std::shared_ptr CSiaFilePtr; typedef std::vector CSiaFileCollection; diff --git a/include/siadrive_api/siacommon.h b/include/siadrive_api/siacommon.h index 4fc624e..172d106 100644 --- a/include/siadrive_api/siacommon.h +++ b/include/siadrive_api/siacommon.h @@ -30,8 +30,8 @@ #define _WIN32_WINNT_WIN10 0x0A00 // Windows 10 // Windows 8.1 or above supported - #define WINVER _WIN32_WINNT_WINBLUE - #define _WIN32_WINNT _WIN32_WINNT_WINBLUE + #define WINVER _WIN32_WINNT_WIN7 + #define _WIN32_WINNT _WIN32_WINNT_WIN7 #define _WINSOCKAPI_ #include #include @@ -68,6 +68,8 @@ using json = nlohmann::json; #define NS_END(c) NS_END##c() +#define COMMA , + NS_BEGIN(Sia) NS_BEGIN(Api) @@ -87,7 +89,7 @@ typedef ttmath::Big<1, 30> SiaCurrency; const std::uint8_t SIA_BLOCK_TIME_MINS = 10; const std::uint32_t MINUTES_PER_MONTH = (730 * 60); const std::uint32_t SIA_BLOCKS_PER_MONTH = MINUTES_PER_MONTH / SIA_BLOCK_TIME_MINS; -const std::uint32_t SIA_DEFAULT_HOST_COUNT = 50; +const std::uint32_t SIA_DEFAULT_HOST_COUNT = 24; const std::uint32_t SIA_DEFAULT_RENEW_WINDOW = ((1440 / SIA_BLOCK_TIME_MINS) * 14); const SiaCurrency SIA_DEFAULT_MINIMUM_FUNDS = 4000; const std::uint32_t SIA_DEFAULT_CONTRACT_LENGTH = SIA_BLOCKS_PER_MONTH * 3; @@ -131,7 +133,7 @@ public: public: Property(T, Code, public, private) - Property(SString, Reason, public, private) + Property(SString, Reason, public, private) public: operator bool() { return GetCode() == T::Success; } @@ -189,41 +191,16 @@ inline static SString SiaCurrencyToGB(const SiaCurrency& value) return value.ToWString(conv); } -class IHost +inline static Hastings SiaCurrencyToHastings(const SiaCurrency& currency) { -public: - IHost() {} - virtual ~IHost() {} + ttmath::Parser parser; + parser.Parse(currency.ToString() + " * (10 ^ 24)"); -public: - virtual Hastings GetStoragePrice() const = 0; - virtual Hastings GetDownloadPrice() const = 0; - virtual Hastings GetUploadPrice() const = 0; -}; - -template -inline static R CalculateAveragePrice(const std::vector& v, std::function PriceGetter) -{ - R result = v.size() ? std::accumulate(std::next(v.begin()), v.end(), PriceGetter(v[0]), [&](const R& a, const T& b) { - return a + PriceGetter(b); - }).Div(v.size()) : 0; - - return result; -} - -inline static Hastings CalculateAverageHostPrice(const std::vector& hosts) -{ - return CalculateAveragePrice(hosts, [](const IHost& host)->Hastings { return host.GetStoragePrice(); }); -} - -inline static Hastings CalculateAverageDownloadPrice(const std::vector& hosts) -{ - return CalculateAveragePrice(hosts, [](const IHost& host)->Hastings { return host.GetDownloadPrice(); }); -} - -inline static Hastings CalculateAverageUploadPrice(const std::vector& hosts) -{ - return CalculateAveragePrice(hosts, [](const IHost& host)->Hastings { return host.GetUploadPrice(); }); + ttmath::Conv conv; + conv.scient_from = 256; + conv.base = 10; + conv.round = 0; + return parser.stack[0].value.ToString(conv); } BOOL SIADRIVE_EXPORTABLE RetryAction(std::function func, std::uint16_t retryCount, const DWORD& retryDelay); diff --git a/src/siadrive_api/siaapi.cpp b/src/siadrive_api/siaapi.cpp index 331ef66..e144d3e 100644 --- a/src/siadrive_api/siaapi.cpp +++ b/src/siadrive_api/siaapi.cpp @@ -11,6 +11,7 @@ CSiaApi::CSiaApi(const SiaHostConfig& hostConfig, CSiaDriveConfig* siaDriveConfi _wallet(new CSiaWallet(_siaCurl, siaDriveConfig)), _renter(new CSiaRenter(_siaCurl, siaDriveConfig)), _consensus(new CSiaConsensus(_siaCurl, siaDriveConfig)), + _hostDb(new CSiaHostDb(_siaCurl, siaDriveConfig)), _refreshThread(new CAutoThread(_siaCurl, _siaDriveConfig, [this] (const CSiaCurl& siaCurl, CSiaDriveConfig* siaDriveConfig) { this->Refresh(siaCurl, siaDriveConfig); })) { _refreshThread->StartAutoThread(); @@ -28,6 +29,7 @@ void CSiaApi::Refresh(const CSiaCurl& siaCurl, CSiaDriveConfig* siaDriveConfig) this->_wallet->Refresh(siaCurl, siaDriveConfig); this->_consensus->Refresh(siaCurl, siaDriveConfig); this->_renter->Refresh(siaCurl, siaDriveConfig); + this->_hostDb->Refresh(siaCurl, siaDriveConfig); } SString CSiaApi::FormatToSiaPath(SString path) @@ -72,6 +74,11 @@ CSiaConsensusPtr CSiaApi::GetConsensus() const return _consensus; } +CSiaHostDbPtr CSiaApi::GetHostDb() const +{ + return _hostDb; +} + SiaHostConfig CSiaApi::GetHostConfig() const { return _hostConfig; diff --git a/src/siadrive_api/siahost.cpp b/src/siadrive_api/siahost.cpp new file mode 100644 index 0000000..c0fe707 --- /dev/null +++ b/src/siadrive_api/siahost.cpp @@ -0,0 +1,82 @@ +#include + +using namespace Sia::Api; +/* +{ + // true if the host is accepting new contracts. + "acceptingcontracts": true, + + // Maximum number of bytes that the host will allow to be requested by a + // single download request. + "maxdownloadbatchsize" : 17825792, + + // Maximum duration in blocks that a host will allow for a file contract. + // The host commits to keeping files for the full duration under the + // threat of facing a large penalty for losing or dropping data before + // the duration is complete. The storage proof window of an incoming file + // contract must end before the current height + maxduration. + // + // There is a block approximately every 10 minutes. + // e.g. 1 day = 144 blocks + "maxduration": 25920, + + // Maximum size in bytes of a single batch of file contract + // revisions. Larger batch sizes allow for higher throughput as there is + // significant communication overhead associated with performing a batch + // upload. + "maxrevisebatchsize": 17825792, + + // Remote address of the host. It can be an IPv4, IPv6, or hostname, + // along with the port. IPv6 addresses are enclosed in square brackets. + "netaddress" : "123.456.789.0:9982", + + // Unused storage capacity the host claims it has, in bytes. + "remainingstorage" : 35000000000, + + // Smallest amount of data in bytes that can be uploaded or downloaded to + // or from the host. + "sectorsize" : 4194304, + + // Total amount of storage capacity the host claims it has, in bytes. + "totalstorage" : 35000000000, + + // Address at which the host can be paid when forming file contracts. + "unlockhash" : "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789ab", + + // A storage proof window is the number of blocks that the host has to + // get a storage proof onto the blockchain. The window size is the + // minimum size of window that the host will accept in a file contract. + "windowsize" : 144, + + // Public key used to identify and verify hosts. + "publickey" : { + // Algorithm used for signing and verification. Typically "ed25519". + "algorithm": "ed25519", + + // Key used to verify signed host messages. + "key" : "RW50cm9weSBpc24ndCB3aGF0IGl0IHVzZWQgdG8gYmU=" + } +} +*/ + +CSiaApi::_CSiaHost::_CSiaHost(const CSiaCurl& siaCurl, CSiaDriveConfig* siaDriveConfig, const json& hostJson) : + CSiaBase(siaCurl, siaDriveConfig), + _AcceptingContracts(hostJson["acceptingcontracts"].get()), + _MaxDownloadBatchSize(hostJson["maxdownloadbatchsize"].get()), + _MaxDuration(hostJson["maxduration"].get()), + _MaxReviseBatchSize(hostJson["maxrevisebatchsize"].get()), + _NetAddress(hostJson["netaddress"].get()), + _RemainingStorage(hostJson["remainingstorage"].get()), + _SectorSize(hostJson["sectorsize"].get()), + _TotalStorage(hostJson["totalstorage"].get()), + _UnlockHash(hostJson["unlockhash"].get()), + _WindowSize(hostJson["windowsize"].get()), + _PublicKey({hostJson["publickey"]["algorithm"].get(), hostJson["publickey"]["key"].get()}) +{ + +} + +CSiaApi::_CSiaHost::~_CSiaHost() +{ + +} diff --git a/src/siadrive_api/siahostdb.cpp b/src/siadrive_api/siahostdb.cpp new file mode 100644 index 0000000..81076d3 --- /dev/null +++ b/src/siadrive_api/siahostdb.cpp @@ -0,0 +1,33 @@ +#include + +using namespace Sia::Api; + +CSiaApi::_CSiaHostDb::_CSiaHostDb(const CSiaCurl& siaCurl, CSiaDriveConfig* siaDriveConfig) : + CSiaBase(siaCurl, siaDriveConfig) +{ +} + +CSiaApi::_CSiaHostDb::~_CSiaHostDb() +{ +} + +void CSiaApi::_CSiaHostDb::Refresh(const CSiaCurl& siaCurl, CSiaDriveConfig* siaDriveConfig) +{ + CSiaHostCollectionPtr hostCollection(new CSiaHostCollection()); + json result; + if (ApiSuccess(siaCurl.Get(L"/hostdb/active", result))) + { + auto hosts = result["hosts"]; + for (const auto& host : hosts) + { + CSiaHostPtr hostPtr(new CSiaHost(siaCurl, siaDriveConfig, host)); + hostCollection->push_back(hostPtr); + } + } + _activeHosts = hostCollection; +} + +CSiaHostCollectionPtr CSiaApi::_CSiaHostDb::GetActiveHosts() const +{ + return _activeHosts; +} \ No newline at end of file diff --git a/src/siadrive_api/siarenter.cpp b/src/siadrive_api/siarenter.cpp index af5b384..d332fbc 100644 --- a/src/siadrive_api/siarenter.cpp +++ b/src/siadrive_api/siarenter.cpp @@ -223,5 +223,27 @@ SiaApiError CSiaApi::_CSiaRenter::SetAllowance(const SiaRenterAllowance& renterA ret = { SiaApiErrorCode::RequestError, cerror.GetReason() }; } + return ret; +} + +SiaApiError CSiaApi::_CSiaRenter::CalculateEstimatedStorage(const SiaCurrency& funds, SiaCurrency& resultGb) const +{ + SiaApiError ret; + json result; + SiaCurlError cerror = GetSiaCurl().Get(L"/renter/prices", {}, result); + if (ApiSuccess(cerror)) + { + ret = { SiaApiErrorCode::RequestError, cerror.GetReason() }; + } + else + { + Hastings fundsHastings = SiaCurrencyToHastings(funds); + ttmath::Parser parser; + parser.Parse(fundsHastings.ToString() + " / " + result["storageterabytemonth"].get() + " * 1000000000000"); + resultGb = parser.stack[0].value; + } + + //const estimate = new BigNumber(SiaAPI.siacoinsToHastings(action.funds)).dividedBy(response.storageterabytemonth).times(1e12) + return ret; } \ No newline at end of file