refactor(audit): batch 7 — RPC/settings/lite/effects mechanical dedups
Six behavior-preserving consolidations from the audit: - RPCClient::call() overloads share a private performCall() (payload dump + curl_easy_perform + http code) and a static parseRpcResult() (error->RpcError extraction). The timeout overload restores the prior timeout in both the success and catch paths, exactly as before. - The six UnifiedCallback methods delegate to one splitUnified() that builds the (Callback, ErrorCallback) pair once (null-check preserved). - One liteTrimCopy() in lite_connection_service replaces 5 file-local trim-copy helpers across the lite slice. - lite_wallet_controller's inline height JSON parse now routes through the tested parseLiteHeightResponse(). - theme_effects.cpp: unpackRGB()/scaledAlpha() replace 14 RGB-unpack + 5 alpha-scale copy-paste blocks. - settings.cpp load() uses loadScalar()/loadClamped() helpers for ~44 scalar fields. Besides removing boilerplate this HARDENS loading: ~44 fields that previously only checked contains() now also verify the JSON type, so a malformed value in settings.json falls back to the default instead of throwing/misreading. Custom cases (enum parses, legacy migrations, arrays) stay inline; save() is unchanged. Full-node + Lite build clean; ctest 1/1; hygiene clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -13,17 +13,6 @@ namespace wallet {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string trimCopy(const std::string& value)
|
||||
{
|
||||
auto begin = value.begin();
|
||||
while (begin != value.end() && std::isspace(static_cast<unsigned char>(*begin))) ++begin;
|
||||
|
||||
auto end = value.end();
|
||||
while (end != begin && std::isspace(static_cast<unsigned char>(*(end - 1)))) --end;
|
||||
|
||||
return std::string(begin, end);
|
||||
}
|
||||
|
||||
bool startsWith(const std::string& value, const char* prefix)
|
||||
{
|
||||
const std::string prefixValue(prefix);
|
||||
@@ -34,7 +23,7 @@ bool startsWith(const std::string& value, const char* prefix)
|
||||
LiteServerEndpoint trimmedEndpoint(const LiteServerEndpoint& endpoint)
|
||||
{
|
||||
LiteServerEndpoint normalized = endpoint;
|
||||
normalized.url = trimCopy(normalized.url);
|
||||
normalized.url = liteTrimCopy(normalized.url);
|
||||
return normalized;
|
||||
}
|
||||
|
||||
@@ -52,12 +41,23 @@ std::vector<std::pair<std::size_t, LiteServerEndpoint>> usableConfiguredServers(
|
||||
|
||||
std::string normalizedChainName(const std::string& chainName)
|
||||
{
|
||||
const std::string normalized = trimCopy(chainName);
|
||||
const std::string normalized = liteTrimCopy(chainName);
|
||||
return normalized.empty() ? kDragonXLiteChainName : normalized;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string liteTrimCopy(const std::string& value)
|
||||
{
|
||||
auto begin = value.begin();
|
||||
while (begin != value.end() && std::isspace(static_cast<unsigned char>(*begin))) ++begin;
|
||||
|
||||
auto end = value.end();
|
||||
while (end != begin && std::isspace(static_cast<unsigned char>(*(end - 1)))) --end;
|
||||
|
||||
return std::string(begin, end);
|
||||
}
|
||||
|
||||
std::vector<LiteServerEndpoint> defaultDragonXLiteServers()
|
||||
{
|
||||
return {
|
||||
@@ -83,13 +83,13 @@ LiteConnectionSettings defaultLiteConnectionSettings()
|
||||
|
||||
bool isLiteServerUrlUsable(const std::string& serverUrl)
|
||||
{
|
||||
const std::string normalized = trimCopy(serverUrl);
|
||||
const std::string normalized = liteTrimCopy(serverUrl);
|
||||
return startsWith(normalized, "https://") || startsWith(normalized, "http://");
|
||||
}
|
||||
|
||||
bool isOfficialLiteServer(const std::string& serverUrl)
|
||||
{
|
||||
const std::string url = trimCopy(serverUrl);
|
||||
const std::string url = liteTrimCopy(serverUrl);
|
||||
for (const auto& s : defaultDragonXLiteServers())
|
||||
if (s.url == url) return true;
|
||||
return false;
|
||||
@@ -126,7 +126,7 @@ const char* liteConnectionAvailabilityName(LiteConnectionAvailability availabili
|
||||
LiteServerSelectionResult selectLiteServer(const LiteConnectionSettings& settings)
|
||||
{
|
||||
auto usableServers = usableConfiguredServers(settings);
|
||||
const std::string stickyServerUrl = trimCopy(settings.stickyServerUrl);
|
||||
const std::string stickyServerUrl = liteTrimCopy(settings.stickyServerUrl);
|
||||
|
||||
if (settings.selectionMode == LiteServerSelectionMode::Sticky &&
|
||||
isLiteServerUrlUsable(stickyServerUrl)) {
|
||||
|
||||
@@ -84,6 +84,8 @@ struct LiteServerHealthCheckResult {
|
||||
std::string error;
|
||||
};
|
||||
|
||||
// Trims leading/trailing whitespace, returning a copy. Shared across the lite slice.
|
||||
std::string liteTrimCopy(const std::string& value);
|
||||
std::vector<LiteServerEndpoint> defaultDragonXLiteServers();
|
||||
LiteConnectionSettings defaultLiteConnectionSettings();
|
||||
bool isLiteServerUrlUsable(const std::string& serverUrl);
|
||||
|
||||
@@ -1,24 +1,12 @@
|
||||
#include "wallet/lite_sync_service.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
namespace dragonx::wallet {
|
||||
namespace {
|
||||
|
||||
std::string trimSyncCopy(const std::string& value)
|
||||
{
|
||||
auto begin = value.begin();
|
||||
while (begin != value.end() && std::isspace(static_cast<unsigned char>(*begin))) ++begin;
|
||||
|
||||
auto end = value.end();
|
||||
while (end != begin && std::isspace(static_cast<unsigned char>(*(end - 1)))) --end;
|
||||
|
||||
return std::string(begin, end);
|
||||
}
|
||||
|
||||
std::uint64_t effectiveStagnantThreshold(std::uint64_t threshold)
|
||||
{
|
||||
return threshold == 0 ? 1 : threshold;
|
||||
@@ -283,7 +271,7 @@ LiteSyncStatusResult LiteSyncService::pollSyncStatus(const LiteSyncStatusRequest
|
||||
|
||||
LiteServerSelectionResult LiteSyncService::selectServerForRequest(const std::string& serverUrl) const
|
||||
{
|
||||
const auto overrideUrl = trimSyncCopy(serverUrl);
|
||||
const auto overrideUrl = liteTrimCopy(serverUrl);
|
||||
if (!overrideUrl.empty()) {
|
||||
if (!isLiteServerUrlUsable(overrideUrl)) {
|
||||
return LiteServerSelectionResult{false, {}, 0, false, "lite sync server URL is not usable"};
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "lite_wallet_controller.h"
|
||||
|
||||
#include "lite_diagnostics.h"
|
||||
#include "lite_result_parsers.h"
|
||||
#include "../data/wallet_state.h"
|
||||
|
||||
#include <algorithm>
|
||||
@@ -695,19 +696,14 @@ std::optional<LiteWalletAppRefreshModel> LiteWalletController::refreshModel()
|
||||
if (bridge_) {
|
||||
const auto h = bridge_->execute("height", "");
|
||||
if (h.ok) {
|
||||
try {
|
||||
const auto j = nlohmann::json::parse(h.value);
|
||||
if (j.is_object() && j.contains("height") && j["height"].is_number_unsigned()) {
|
||||
const unsigned long long height = j["height"].get<unsigned long long>();
|
||||
if (height > 0) {
|
||||
model.hasSyncStatus = true;
|
||||
model.sync.walletHeight = height;
|
||||
model.sync.chainHeight = height; // synced: wallet height == chain tip
|
||||
model.sync.complete = true;
|
||||
model.sync.progress = 1.0;
|
||||
}
|
||||
}
|
||||
} catch (...) { /* leave the mapped sync fields as-is */ }
|
||||
const auto parsed = parseLiteHeightResponse(h.value);
|
||||
if (parsed.ok && parsed.height.height > 0) {
|
||||
model.hasSyncStatus = true;
|
||||
model.sync.walletHeight = parsed.height.height;
|
||||
model.sync.chainHeight = parsed.height.height; // synced: wallet height == chain tip
|
||||
model.sync.complete = true;
|
||||
model.sync.progress = 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return model;
|
||||
|
||||
@@ -1,22 +1,10 @@
|
||||
#include "wallet/lite_wallet_gateway.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <utility>
|
||||
|
||||
namespace dragonx::wallet {
|
||||
namespace {
|
||||
|
||||
std::string trimGatewayCopy(const std::string& value)
|
||||
{
|
||||
auto begin = value.begin();
|
||||
while (begin != value.end() && std::isspace(static_cast<unsigned char>(*begin))) ++begin;
|
||||
|
||||
auto end = value.end();
|
||||
while (end != begin && std::isspace(static_cast<unsigned char>(*(end - 1)))) --end;
|
||||
|
||||
return std::string(begin, end);
|
||||
}
|
||||
|
||||
WalletBackendStatus makeGatewayStatus(WalletBackendState state, std::string message)
|
||||
{
|
||||
WalletBackendStatus status;
|
||||
@@ -262,7 +250,7 @@ LiteWalletRefreshResult LiteWalletGateway::refresh(const LiteWalletRefreshReques
|
||||
|
||||
LiteServerSelectionResult LiteWalletGateway::selectServerForRequest(const std::string& serverUrl) const
|
||||
{
|
||||
const auto overrideUrl = trimGatewayCopy(serverUrl);
|
||||
const auto overrideUrl = liteTrimCopy(serverUrl);
|
||||
if (!overrideUrl.empty()) {
|
||||
if (!isLiteServerUrlUsable(overrideUrl)) {
|
||||
return LiteServerSelectionResult{false, {}, 0, false, "lite gateway server URL is not usable"};
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#include "lite_wallet_lifecycle_service.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <utility>
|
||||
|
||||
namespace dragonx {
|
||||
@@ -12,17 +11,6 @@ namespace wallet {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string trimLifecycleCopy(const std::string& value)
|
||||
{
|
||||
auto begin = value.begin();
|
||||
while (begin != value.end() && std::isspace(static_cast<unsigned char>(*begin))) ++begin;
|
||||
|
||||
auto end = value.end();
|
||||
while (end != begin && std::isspace(static_cast<unsigned char>(*(end - 1)))) --end;
|
||||
|
||||
return std::string(begin, end);
|
||||
}
|
||||
|
||||
LiteRedactedPrivateData redactedField(LitePrivateDataKind kind, const std::string& value)
|
||||
{
|
||||
return LiteRedactedPrivateData{kind, !value.empty(), redactLitePrivateDataValue(value)};
|
||||
@@ -172,7 +160,7 @@ LiteWalletLifecyclePlan LiteWalletLifecycleService::planOpenWallet(
|
||||
LiteWalletLifecyclePlan LiteWalletLifecycleService::planRestoreWallet(
|
||||
const LiteWalletRestoreRequest& request) const
|
||||
{
|
||||
const std::string validationError = trimLifecycleCopy(request.seedPhrase).empty()
|
||||
const std::string validationError = liteTrimCopy(request.seedPhrase).empty()
|
||||
? "restore seed phrase is required"
|
||||
: std::string();
|
||||
return makePlan(LiteWalletLifecycleOperation::RestoreFromSeed,
|
||||
@@ -220,7 +208,7 @@ LiteWalletLifecycleResult LiteWalletLifecycleService::restoreWallet(
|
||||
LiteServerSelectionResult LiteWalletLifecycleService::selectServerForRequest(
|
||||
const std::string& serverUrl) const
|
||||
{
|
||||
const std::string overrideUrl = trimLifecycleCopy(serverUrl);
|
||||
const std::string overrideUrl = liteTrimCopy(serverUrl);
|
||||
if (!overrideUrl.empty()) {
|
||||
if (!isLiteServerUrlUsable(overrideUrl)) {
|
||||
return LiteServerSelectionResult{false, {}, 0, false, "lite lifecycle server URL is not usable"};
|
||||
|
||||
@@ -1,25 +1,10 @@
|
||||
#include "lite_wallet_server_selection_adapter.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
namespace dragonx {
|
||||
namespace wallet {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string trimCopy(const std::string& value)
|
||||
{
|
||||
const auto first = std::find_if_not(value.begin(), value.end(), [](unsigned char ch) {
|
||||
return std::isspace(ch) != 0;
|
||||
});
|
||||
const auto last = std::find_if_not(value.rbegin(), value.rend(), [](unsigned char ch) {
|
||||
return std::isspace(ch) != 0;
|
||||
}).base();
|
||||
if (first >= last) return {};
|
||||
return std::string(first, last);
|
||||
}
|
||||
|
||||
LiteServerSelectionMode walletModeFromSettings(
|
||||
config::Settings::LiteServerSelectionPreferenceMode mode)
|
||||
{
|
||||
@@ -52,14 +37,14 @@ LiteConnectionSettings liteConnectionSettingsFromAppSettings(const config::Setti
|
||||
connectionSettings.servers.clear();
|
||||
for (const auto& server : settings.getLiteServers()) {
|
||||
connectionSettings.servers.push_back(LiteServerEndpoint{
|
||||
trimCopy(server.url),
|
||||
liteTrimCopy(server.url),
|
||||
server.label,
|
||||
server.enabled
|
||||
});
|
||||
}
|
||||
connectionSettings.selectionMode = walletModeFromSettings(settings.getLiteServerSelectionMode());
|
||||
connectionSettings.stickyServerUrl = trimCopy(settings.getLiteStickyServerUrl());
|
||||
connectionSettings.chainName = trimCopy(settings.getLiteChainName());
|
||||
connectionSettings.stickyServerUrl = liteTrimCopy(settings.getLiteStickyServerUrl());
|
||||
connectionSettings.chainName = liteTrimCopy(settings.getLiteChainName());
|
||||
if (connectionSettings.chainName.empty()) connectionSettings.chainName = kDragonXLiteChainName;
|
||||
connectionSettings.randomSelectionSeed = settings.getLiteRandomSelectionSeed();
|
||||
return connectionSettings;
|
||||
@@ -72,24 +57,24 @@ void applyLiteConnectionSettingsToAppSettings(config::Settings& settings,
|
||||
servers.reserve(connectionSettings.servers.size());
|
||||
for (const auto& server : connectionSettings.servers) {
|
||||
servers.push_back(config::Settings::LiteServerPreference{
|
||||
trimCopy(server.url),
|
||||
liteTrimCopy(server.url),
|
||||
server.label,
|
||||
server.enabled
|
||||
});
|
||||
}
|
||||
|
||||
settings.setLiteServerSelectionMode(settingsModeFromWallet(connectionSettings.selectionMode));
|
||||
settings.setLiteStickyServerUrl(trimCopy(connectionSettings.stickyServerUrl));
|
||||
settings.setLiteChainName(trimCopy(connectionSettings.chainName).empty()
|
||||
settings.setLiteStickyServerUrl(liteTrimCopy(connectionSettings.stickyServerUrl));
|
||||
settings.setLiteChainName(liteTrimCopy(connectionSettings.chainName).empty()
|
||||
? kDragonXLiteChainName
|
||||
: trimCopy(connectionSettings.chainName));
|
||||
: liteTrimCopy(connectionSettings.chainName));
|
||||
settings.setLiteRandomSelectionSeed(connectionSettings.randomSelectionSeed);
|
||||
settings.setLiteServers(servers);
|
||||
}
|
||||
|
||||
std::string redactLiteServerSelectionValue(const std::string& value)
|
||||
{
|
||||
const std::string trimmed = trimCopy(value);
|
||||
const std::string trimmed = liteTrimCopy(value);
|
||||
if (trimmed.empty()) return "<empty>";
|
||||
const auto scheme = trimmed.find("://");
|
||||
if (scheme == std::string::npos) return "<redacted>";
|
||||
|
||||
Reference in New Issue
Block a user