diff --git a/src/app.cpp b/src/app.cpp index 7060a25..3bb21f8 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -569,6 +569,12 @@ void App::update() // Wipe a secret (seed/private key) from the clipboard once its auto-clear delay elapses. pumpSecretClipboardClear(); + // Re-apply the refresh cadence when sync starts/finishes: while syncing we throttle polling to + // a low-impact profile so RPC contention doesn't slow block download (see applyRefreshPolicy). + if (state_.sync.syncing != refresh_policy_syncing_) { + applyRefreshPolicy(current_page_); + } + // Full-node RPC refreshes gate on ACTUAL RPC connectivity, not state_.connected. In lite // builds state_.connected is the lite-wallet "online" proxy (true when a wallet is open, to // enable the wallet UI), but there is no RPC daemon — so RPC polls (mining/balance/peers/txs) diff --git a/src/app.h b/src/app.h index 7324b39..bba85cd 100644 --- a/src/app.h +++ b/src/app.h @@ -519,6 +519,7 @@ private: int daemon_wait_attempts_ = 0; bool daemon_start_error_shown_ = false; int daemon_last_seen_crashes_ = 0; // surface each new embedded-daemon crash reason once + bool refresh_policy_syncing_ = false; // whether the sync-throttle refresh profile is active // Auto-clear for secrets copied to the clipboard. Only a hash of the copied secret is kept. std::uint64_t clipboard_secret_hash_ = 0; double clipboard_clear_deadline_ = 0.0; diff --git a/src/app_network.cpp b/src/app_network.cpp index 60fecee..95e88bd 100644 --- a/src/app_network.cpp +++ b/src/app_network.cpp @@ -664,7 +664,14 @@ App::RefreshIntervals App::getIntervalsForPage(ui::NavPage page) void App::applyRefreshPolicy(ui::NavPage page) { - network_refresh_.setIntervals(getIntervalsForPage(page)); + // While the daemon is syncing, override the per-tab cadence with the low-impact sync profile so + // the wallet stops contending for the daemon's cs_main lock (frequent getpeerinfo / per-block + // transaction scans / balance polls slow block connection). This makes every tab sync as fast + // as the Console tab does today. Reverts to the per-tab profile once sync finishes. + refresh_policy_syncing_ = state_.sync.syncing; + network_refresh_.setIntervals(refresh_policy_syncing_ + ? services::RefreshScheduler::kSyncProfile + : getIntervalsForPage(page)); } bool App::currentPageNeedsWalletDataRefresh() const @@ -1159,10 +1166,13 @@ void App::refreshCoreData() ? fast_rpc_.get() : rpc_.get(); if (!w || !rpc) return; ui::NavPage tracePage = current_page_; + // Skip the balance call while syncing (it's incomplete anyway and takes the wallet lock + + // cs_main). Captured on the main thread to avoid reading state_ off the worker thread. + const bool includeBalance = !state_.sync.syncing; - auto enqueued = network_refresh_.enqueue(services::NetworkRefreshService::Job::Core, *w, [this, rpc, tracePage]() -> rpc::RPCWorker::MainCb { + auto enqueued = network_refresh_.enqueue(services::NetworkRefreshService::Job::Core, *w, [this, rpc, tracePage, includeBalance]() -> rpc::RPCWorker::MainCb { AppRefreshRpcGateway refreshRpc(*rpc, traceSource(tracePage, "Core refresh")); - auto result = NetworkRefreshService::collectCoreRefreshResult(refreshRpc); + auto result = NetworkRefreshService::collectCoreRefreshResult(refreshRpc, includeBalance); return [this, result]() { try { NetworkRefreshService::applyCoreRefreshResult(state_, result, std::time(nullptr)); diff --git a/src/services/network_refresh_service.cpp b/src/services/network_refresh_service.cpp index 8c46230..284c5cb 100644 --- a/src/services/network_refresh_service.cpp +++ b/src/services/network_refresh_service.cpp @@ -284,18 +284,20 @@ NetworkRefreshService::CoreRefreshResult NetworkRefreshService::parseCoreRefresh return result; } -NetworkRefreshService::CoreRefreshResult NetworkRefreshService::collectCoreRefreshResult(RefreshRpcGateway& rpc) +NetworkRefreshService::CoreRefreshResult NetworkRefreshService::collectCoreRefreshResult(RefreshRpcGateway& rpc, bool includeBalance) { json totalBalance; json blockInfo; bool balanceOk = false; bool blockOk = false; - try { - totalBalance = rpc.call("z_gettotalbalance", json::array()); - balanceOk = true; - } catch (const std::exception& e) { - DEBUG_LOGF("Balance error: %s\n", e.what()); + if (includeBalance) { + try { + totalBalance = rpc.call("z_gettotalbalance", json::array()); + balanceOk = true; + } catch (const std::exception& e) { + DEBUG_LOGF("Balance error: %s\n", e.what()); + } } try { diff --git a/src/services/network_refresh_service.h b/src/services/network_refresh_service.h index 3037e88..d57041d 100644 --- a/src/services/network_refresh_service.h +++ b/src/services/network_refresh_service.h @@ -230,7 +230,10 @@ public: bool balanceOk, const nlohmann::json& blockInfo, bool blockOk); - static CoreRefreshResult collectCoreRefreshResult(RefreshRpcGateway& rpc); + // includeBalance=false skips z_gettotalbalance (which takes the wallet lock + cs_main) and only + // fetches getblockchaininfo — used while syncing, where the balance is incomplete anyway and the + // wallet should minimise lock contention with block connection. + static CoreRefreshResult collectCoreRefreshResult(RefreshRpcGateway& rpc, bool includeBalance = true); static MiningRefreshResult parseMiningRefreshResult(const nlohmann::json& miningInfo, bool miningOk, const nlohmann::json& localHashrate, diff --git a/src/services/refresh_scheduler.h b/src/services/refresh_scheduler.h index 28367a7..c5adf1e 100644 --- a/src/services/refresh_scheduler.h +++ b/src/services/refresh_scheduler.h @@ -34,6 +34,14 @@ public: static constexpr float kTxMaxAge = 15.0f; static constexpr float kOpidPoll = 2.0f; + // Low-impact polling profile applied while the daemon is SYNCING, regardless of the active tab. + // Only a slow progress poll runs (core, 10s); transactions/addresses/peers are disabled (0). + // Frequent getpeerinfo, per-block transaction scans, and balance polls all contend for the + // daemon's cs_main lock and measurably slow block connection during sync — this is exactly why + // the lightweight Console tab syncs faster than the Peers tab. Reverts to the per-tab profile + // once sync completes. (Tx/address/balance data is incomplete mid-sync anyway.) + static constexpr Intervals kSyncProfile{10.0f, 0.0f, 0.0f, 0.0f}; + static Intervals intervalsForPage(ui::NavPage page); void applyPage(ui::NavPage page);