From 9b44d435f8651d5f1766276698cdd5b1f4e2b2d6 Mon Sep 17 00:00:00 2001 From: "Scott E. Graves" Date: Fri, 17 Feb 2017 18:58:06 -0600 Subject: [PATCH] Refactoring and added common utils --- SiaDrive.Api/SiaCommon.cpp | 33 ++++++++++++++++++- SiaDrive.Api/SiaCommon.h | 48 +++++++++++++++++++++++++--- SiaDrive.Api/SiaConsensus.cpp | 2 +- SiaDrive.Api/SiaCurl.cpp | 6 ++-- SiaDrive.Api/SiaRenter.cpp | 4 +-- SiaDrive.Api/SiaWallet.cpp | 18 +++++------ SiaDrive.Dokan.Api/SiaDokanDrive.cpp | 6 ++-- SiaDrive/SiaDriveDlg.cpp | 8 ++--- UnitTests/SiaWalletApiTests.cpp | 6 ++-- 9 files changed, 101 insertions(+), 30 deletions(-) diff --git a/SiaDrive.Api/SiaCommon.cpp b/SiaDrive.Api/SiaCommon.cpp index 5267f50..7d353a3 100644 --- a/SiaDrive.Api/SiaCommon.cpp +++ b/SiaDrive.Api/SiaCommon.cpp @@ -2,4 +2,35 @@ #include "SiaCommon.h" #include -using namespace Sia::Api; \ No newline at end of file +using namespace Sia::Api; + + +/* +// avgHostMetric computes the average of the metric given by `metric` on the +// list of `hosts`. +const avgHostMetric = (hosts, metric) = > +hosts.reduce((sum, host) = > sum.add(host[metric]), new BigNumber(0)) +.dividedBy(hosts.size) + +// avgStorageCost returns the average storage cost from a list of hosts given a +// period (blocks) and redundancy. +const avgStorageCost = (hosts, period, redundancy) = > +avgHostMetric(hosts, 'storageprice') +.times(period) +.plus(avgHostMetric(hosts, 'uploadbandwidthprice')) +.times(redundancy) +.plus(avgHostMetric(hosts, 'downloadbandwidthprice')) + +// Compute an estimated amount of storage from an amount of funds (Hastings) +// and a list of hosts. +export const estimatedStorage = (funds, hosts) = > { + const validHosts = List(hosts).take(28) + const avgStorage = avgStorageCost(validHosts, allowancePeriod, baseRedundancy) + + let fee = SiaAPI.siacoinsToHastings(baseFee) + fee = fee.plus(avgHostMetric(validHosts, 'contractprice').times(ncontracts)) + fee = fee.plus(funds.minus(fee).times(siafundRate)) + + return '~' + readableFilesize(Math.max(0, funds.minus(fee).dividedBy(avgStorage).toNumber().toPrecision(1))) +} +*/ \ No newline at end of file diff --git a/SiaDrive.Api/SiaCommon.h b/SiaDrive.Api/SiaCommon.h index be6fad8..f470bab 100644 --- a/SiaDrive.Api/SiaCommon.h +++ b/SiaDrive.Api/SiaCommon.h @@ -20,7 +20,8 @@ using json = nlohmann::json; NS_BEGIN(Sia) NS_BEGIN(Api) -#define String std::wstring +typedef std::wstring String; +#define DEFAULT_CONFIG_FILE_PATH L".\\Config\\SiaDriveConfig.json" #define Property(type, name, get_access, set_access) \ private:\ @@ -43,10 +44,12 @@ struct SiaHostConfig String RequiredVersion; }; -#define API_SUCCESS(t, x) (x == t::Success) - -#define DEFAULT_CONFIG_FILE_PATH L".\\Config\\SiaDriveConfig.json" +template +inline bool ApiSuccess(const T& t) { + return t == T::Success; +} +typedef ttmath::UInt<256> Hastings; typedef ttmath::Big<1, 30> SiaCurrency; /* BigNumber.config({ EXPONENTIAL_AT: 1e+9 }) @@ -72,4 +75,41 @@ static inline String SiaCurrencyToString(const SiaCurrency& value) return value.ToWString(conv); } +class IHost +{ +public: + IHost() {} + virtual ~IHost() {} + +public: + virtual Hastings GetStoragePrice() const = 0; + virtual Hastings GetDownloadPrice() const = 0; + virtual Hastings GetUploadPrice() const = 0; +}; + +template +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 Hastings CalculateAverageHostPrice(const std::vector& hosts) +{ + return CalculateAveragePrice(hosts, [](const IHost& host)->Hastings { return host.GetStoragePrice(); }); +} + +inline Hastings CalculateAverageDownloadPrice(const std::vector& hosts) +{ + return CalculateAveragePrice(hosts, [](const IHost& host)->Hastings { return host.GetDownloadPrice(); }); +} + +inline Hastings CalculateAverageUploadPrice(const std::vector& hosts) +{ + return CalculateAveragePrice(hosts, [](const IHost& host)->Hastings { return host.GetUploadPrice(); }); +} + NS_END(2) \ No newline at end of file diff --git a/SiaDrive.Api/SiaConsensus.cpp b/SiaDrive.Api/SiaConsensus.cpp index f10136f..b511944 100644 --- a/SiaDrive.Api/SiaConsensus.cpp +++ b/SiaDrive.Api/SiaConsensus.cpp @@ -24,7 +24,7 @@ void CSiaApi::_CSiaConsensus::StartRefreshThread() do { json result; - if (API_SUCCESS(SiaCurlError, _siaCurl.Get(L"/consensus", result))) + if (ApiSuccess(_siaCurl.Get(L"/consensus", result))) { SetHeight(result["height"].get()); SetSynced(result["synced"].get()); diff --git a/SiaDrive.Api/SiaCurl.cpp b/SiaDrive.Api/SiaCurl.cpp index bee0dae..df6b0bb 100644 --- a/SiaDrive.Api/SiaCurl.cpp +++ b/SiaDrive.Api/SiaCurl.cpp @@ -62,7 +62,7 @@ SiaCurlError CSiaCurl::ProcessResponse(const int& res, const std::string& result if (res == CURLE_OK) { ret = CheckHttpError(result); - if (API_SUCCESS(SiaCurlError, ret)) + if (ApiSuccess(ret)) { ret = (result.length() ? CheckApiError((response = json::parse(result.c_str()))) : SiaCurlError::Success); } @@ -114,13 +114,13 @@ bool CSiaCurl::CheckVersion(SiaCurlError& error) const } } - return API_SUCCESS(SiaCurlError, error); + return ApiSuccess(error); } String CSiaCurl::GetServerVersion() const { json response; - if (API_SUCCESS(SiaCurlError, _Get(L"/daemon/version", response))) + if (ApiSuccess(_Get(L"/daemon/version", response))) { return String(CA2W(response["version"].get().c_str())); } diff --git a/SiaDrive.Api/SiaRenter.cpp b/SiaDrive.Api/SiaRenter.cpp index 057fe12..2d2f357 100644 --- a/SiaDrive.Api/SiaRenter.cpp +++ b/SiaDrive.Api/SiaRenter.cpp @@ -17,7 +17,7 @@ SiaApiError CSiaApi::_CSiaRenter::FileExists(const String& siaPath, bool& exists { CSiaFileTreePtr siaFileTree; SiaApiError ret = GetFileTree(siaFileTree); - if (API_SUCCESS(SiaApiError, ret)) + if (ApiSuccess(ret)) { exists = siaFileTree->FileExists(siaPath); } @@ -44,7 +44,7 @@ SiaApiError CSiaApi::_CSiaRenter::GetFileTree(CSiaFileTreePtr& siaFileTree) cons SiaApiError ret = SiaApiError::RequestError; siaFileTree.reset(new CSiaFileTree(_siaCurl)); json result; - if (API_SUCCESS(SiaCurlError, _siaCurl.Get(L"/renter/files", result))) + if (ApiSuccess(_siaCurl.Get(L"/renter/files", result))) { siaFileTree->BuildTree(result); ret = SiaApiError::Success; diff --git a/SiaDrive.Api/SiaWallet.cpp b/SiaDrive.Api/SiaWallet.cpp index 21d1136..5f4fd2e 100644 --- a/SiaDrive.Api/SiaWallet.cpp +++ b/SiaDrive.Api/SiaWallet.cpp @@ -38,7 +38,7 @@ bool CSiaApi::_CSiaWallet::Refresh() { json result; SiaCurlError error = _siaCurl.Get(L"/wallet", result); - if (API_SUCCESS(SiaCurlError, error)) + if (ApiSuccess(error)) { SetCreated(result["encrypted"].get()); SetLocked(!result["unlocked"].get()); @@ -60,7 +60,7 @@ SiaApiError CSiaApi::_CSiaWallet::Create(const SiaSeedLanguage& seedLanguage, St error = SiaApiError::RequestError; json result; SiaCurlError cerror = _siaCurl.Post(L"/wallet/init", { {L"dictionary", SeedLangToString(seedLanguage)} }, result); - if (API_SUCCESS(SiaCurlError, cerror)) + if (ApiSuccess(cerror)) { error = SiaApiError::Success; seed = CA2W(result["primaryseed"].get().c_str()); @@ -82,13 +82,13 @@ SiaApiError CSiaApi::_CSiaWallet::Restore(const String& seed) SiaApiError CSiaApi::_CSiaWallet::Lock() { SiaApiError error = GetCreated() ? (GetLocked() ? SiaApiError::WalletLocked : SiaApiError::Success) : SiaApiError::WalletNotCreated; - if (API_SUCCESS(SiaApiError, error)) + if (ApiSuccess(error)) { error = SiaApiError::RequestError; json result; SiaCurlError cerror = _siaCurl.Post(L"/wallet/lock", {}, result); - if (API_SUCCESS(SiaCurlError, cerror)) + if (ApiSuccess(cerror)) { Refresh(); error = SiaApiError::Success; @@ -101,13 +101,13 @@ SiaApiError CSiaApi::_CSiaWallet::Lock() SiaApiError CSiaApi::_CSiaWallet::Unlock(const String& password) { SiaApiError error = GetCreated() ? (GetLocked() ? SiaApiError::Success : SiaApiError::WalletUnlocked) : SiaApiError::WalletNotCreated; - if (API_SUCCESS(SiaApiError, error)) + if (ApiSuccess(error)) { error = SiaApiError::RequestError; json result; SiaCurlError cerror = _siaCurl.Post(L"/wallet/unlock", { {L"encryptionpassword", password} }, result); - if (API_SUCCESS(SiaCurlError, cerror)) + if (ApiSuccess(cerror)) { Refresh(); error = SiaApiError::Success; @@ -135,7 +135,7 @@ SiaApiError CSiaApi::_CSiaWallet::GetConfirmedBalance(SiaCurrency& balance) cons json result; SiaCurlError cerror = _siaCurl.Get(L"/wallet", result); - if (API_SUCCESS(SiaCurlError, cerror)) + if (ApiSuccess(cerror)) { balance = HastingsStringToSiaCurrency(String(CA2W(result["confirmedsiacoinbalance"].get().c_str()))); ret = SiaApiError::Success; @@ -151,7 +151,7 @@ SiaApiError CSiaApi::_CSiaWallet::GetUnonfirmedBalance(SiaCurrency& balance) con json result; SiaCurlError cerror = _siaCurl.Get(L"/wallet", result); - if (API_SUCCESS(SiaCurlError, cerror)) + if (ApiSuccess(cerror)) { balance = HastingsStringToSiaCurrency(String(CA2W(result["unconfirmedincomingsiacoins"].get().c_str()))); ret = SiaApiError::Success; @@ -167,7 +167,7 @@ SiaApiError CSiaApi::_CSiaWallet::GetAddress(String& address) const json result; SiaCurlError cerror = _siaCurl.Get(L"/wallet/address", result); - if (API_SUCCESS(SiaCurlError, cerror)) + if (ApiSuccess(cerror)) { address = CA2W(result["address"].get().c_str()); ret = SiaApiError::Success; diff --git a/SiaDrive.Dokan.Api/SiaDokanDrive.cpp b/SiaDrive.Dokan.Api/SiaDokanDrive.cpp index 96093f6..f72bb60 100644 --- a/SiaDrive.Dokan.Api/SiaDokanDrive.cpp +++ b/SiaDrive.Dokan.Api/SiaDokanDrive.cpp @@ -42,7 +42,7 @@ private: tempPath.resize(MAX_PATH + 1); if (GetTempPath(MAX_PATH + 1, &tempPath[0])) { - ret = API_SUCCESS(SiaApiError, _siaApi->GetRenter()->DownloadFile(siaPath, tempPath)); + ret = ApiSuccess(_siaApi->GetRenter()->DownloadFile(siaPath, tempPath)); if (ret) { @@ -158,7 +158,7 @@ private: else { bool exists; - if (API_SUCCESS(SiaApiError, _siaApi->GetRenter()->FileExists(siaPath, exists))) + if (ApiSuccess(_siaApi->GetRenter()->FileExists(siaPath, exists))) { // Operations on existing files that are requested to be truncated, overwritten or re-created // will first be deleted and then replaced if, after the file operation is done, the resulting file @@ -227,7 +227,7 @@ private: // If file isn't cached, delete from Sia only if (!PathFileExists(cacheFilePath.c_str()) || ::DeleteFile(cacheFilePath.c_str())) { - if (!API_SUCCESS(SiaApiError, _siaApi->GetRenter()->DeleteFile(siaPath))) + if (!ApiSuccess(_siaApi->GetRenter()->DeleteFile(siaPath))) { ret = STATUS_INVALID_SERVER_STATE; } diff --git a/SiaDrive/SiaDriveDlg.cpp b/SiaDrive/SiaDriveDlg.cpp index 46d388b..c6ca88d 100644 --- a/SiaDrive/SiaDriveDlg.cpp +++ b/SiaDrive/SiaDriveDlg.cpp @@ -319,7 +319,7 @@ HRESULT CSiaDriveDlg::OnButtonUnlockWallet(IHTMLElement* /*pElement*/) SetBodyEnabled(false); String pwd = GetWalletUnlockPassword(); std::thread th([this, pwd]() { - if (API_SUCCESS(SiaApiError, _siaApi.GetWallet()->Unlock(pwd))) + if (ApiSuccess(_siaApi.GetWallet()->Unlock(pwd))) { QueueUiAction([this]() { SetWalletUnlockPassword(L""); @@ -501,10 +501,10 @@ bool CSiaDriveDlg::UpdateSiaInfo() if (_siaApi.GetWallet()->Refresh()) { SiaCurrency confirmed; - if (API_SUCCESS(SiaApiError, _siaApi.GetWallet()->GetConfirmedBalance(confirmed))) + if (ApiSuccess(_siaApi.GetWallet()->GetConfirmedBalance(confirmed))) { SiaCurrency unconfirmed; - if (API_SUCCESS(SiaApiError, _siaApi.GetWallet()->GetUnonfirmedBalance(unconfirmed))) + if (ApiSuccess(_siaApi.GetWallet()->GetUnonfirmedBalance(unconfirmed))) { SiaCurrency total = confirmed + unconfirmed; @@ -708,7 +708,7 @@ HRESULT CSiaDriveDlg::OnButtonCreateWallet(IHTMLElement* pElement) KillTimer(IDT_UPDATE); String seed; - if (API_SUCCESS(SiaApiError, _siaApi.GetWallet()->Create(SiaSeedLanguage::English, seed))) + if (ApiSuccess(_siaApi.GetWallet()->Create(SiaSeedLanguage::English, seed))) { DisplaySeedCreated(seed); } diff --git a/UnitTests/SiaWalletApiTests.cpp b/UnitTests/SiaWalletApiTests.cpp index 4d76ba7..ba13ace 100644 --- a/UnitTests/SiaWalletApiTests.cpp +++ b/UnitTests/SiaWalletApiTests.cpp @@ -23,15 +23,15 @@ namespace UnitTests Assert::IsTrue(wallet->GetLocked()); String seed; - Assert::IsTrue(API_SUCCESS(SiaApiError, wallet->Create(SiaSeedLanguage::English, seed))); + Assert::IsTrue(ApiSuccess(wallet->Create(SiaSeedLanguage::English, seed))); Assert::IsTrue(wallet->GetCreated()); Assert::IsTrue(wallet->GetLocked()); - Assert::IsTrue(API_SUCCESS(SiaApiError, wallet->Unlock(seed))); + Assert::IsTrue(ApiSuccess(wallet->Unlock(seed))); Assert::IsTrue(wallet->GetCreated()); Assert::IsFalse(wallet->GetLocked()); - Assert::IsTrue(API_SUCCESS(SiaApiError, wallet->Lock( ))); + Assert::IsTrue(ApiSuccess(wallet->Lock( ))); Assert::IsTrue(wallet->GetCreated()); Assert::IsTrue(wallet->GetLocked()); }