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:
2026-07-02 19:56:54 -05:00
parent 4635a56e89
commit dcd09dc542
11 changed files with 245 additions and 328 deletions

View File

@@ -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;