Reduce redundant RPC calls in periodic refresh cycle

- Remove getinfo from refreshMiningInfo slow path; daemon_version,
  protocol_version, and p2p_port are static per connection (set in
  onConnected). Move longestchain/notarized into refreshBalance's
  existing getblockchaininfo callback.

- Remove refreshMiningInfo from refreshData(); it already runs on
  the 1-second fast_refresh_timer_ independently.

- Make refreshAddresses demand-driven via addresses_dirty_ flag;
  only re-fetch when a new address is created or a send completes,
  not unconditionally every 5 seconds.

- Gate refreshPeerInfo to only run when the Peers tab is active.

- Skip duplicate getwalletinfo on connect; onConnected() already
  prefetches it for immediate lock-screen display, so suppress the
  redundant call in the first refreshData() cycle.

Steady-state savings: ~8 fewer RPC calls per 5-second cycle
(from ~12+ down to ~4-5 in the common case).
This commit is contained in:
2026-02-27 02:28:29 -06:00
parent 721fb292c4
commit 48ce983966
3 changed files with 151 additions and 44 deletions

View File

@@ -187,6 +187,13 @@ void App::onConnected()
});
}
// onConnected already fetched getwalletinfo — tell refreshData to skip
// the duplicate call on the very first cycle.
encryption_state_prefetched_ = true;
// Addresses are unknown on fresh connect — force a fetch
addresses_dirty_ = true;
// Initial data refresh
refreshData();
refreshMarketData();
@@ -211,11 +218,28 @@ void App::refreshData()
if (refresh_in_progress_.exchange(true)) return;
refreshBalance();
refreshAddresses();
// Addresses: only re-fetch when explicitly dirtied (new address, send, etc.)
if (addresses_dirty_) {
refreshAddresses();
}
refreshTransactions();
refreshMiningInfo();
refreshPeerInfo();
refreshWalletEncryptionState();
// Mining: handled by the 1-second fast_refresh_timer_ — skip here to
// avoid queuing a redundant call every 5 seconds.
// Peers: only fetch when the Peers tab is visible
if (current_page_ == ui::NavPage::Peers) {
refreshPeerInfo();
}
// Encryption state: skip if onConnected() already prefetched it
if (encryption_state_prefetched_) {
encryption_state_prefetched_ = false;
} else {
refreshWalletEncryptionState();
}
// Clear the guard after all tasks are posted (they'll execute sequentially
// on the worker thread, so the last one to finish signals completion).
@@ -270,6 +294,13 @@ void App::refreshBalance()
if (blockInfo.contains("verificationprogress"))
state_.sync.verification_progress = blockInfo["verificationprogress"].get<double>();
state_.sync.syncing = (state_.sync.blocks < state_.sync.headers - 2);
// Consolidate chain-tip fields that were previously fetched
// via a separate getinfo call in refreshMiningInfo.
if (blockInfo.contains("longestchain"))
state_.longestchain = blockInfo["longestchain"].get<int>();
if (blockInfo.contains("notarized"))
state_.notarized = blockInfo["notarized"].get<int>();
}
// Auto-shield transparent funds if enabled
@@ -391,6 +422,8 @@ void App::refreshAddresses()
state_.t_addresses = std::move(tAddrs);
// P8: single rebuild via dirty flag (drains in update())
address_list_dirty_ = true;
// Addresses fetched successfully — clear the demand flag
addresses_dirty_ = false;
};
});
}
@@ -583,13 +616,16 @@ void App::refreshMiningInfo()
daemonMemMb = embedded_daemon_->getMemoryUsageMB();
}
// Slow-tick counter: run full getmininginfo + getinfo every ~5 seconds
// Slow-tick counter: run full getmininginfo every ~5 seconds
// to reduce RPC overhead. getlocalsolps (returns H/s for RandomX) runs every tick (1s).
// NOTE: getinfo is NOT called here — longestchain/notarized are updated by
// refreshBalance (via getblockchaininfo), and daemon_version/protocol_version/
// p2p_port are static for the lifetime of a connection (set in onConnected).
bool doSlowRefresh = (mining_slow_counter_++ % 5 == 0);
worker_->post([this, daemonMemMb, doSlowRefresh]() -> rpc::RPCWorker::MainCb {
json miningInfo, localHashrateJson, nodeInfo;
bool miningOk = false, hashrateOk = false, nodeOk = false;
json miningInfo, localHashrateJson;
bool miningOk = false, hashrateOk = false;
// Fast path: only getlocalsolps (single RPC call, ~1ms) — returns H/s (RandomX)
try {
@@ -599,7 +635,7 @@ void App::refreshMiningInfo()
DEBUG_LOGF("getLocalHashrate error: %s\n", e.what());
}
// Slow path: getmininginfo + getinfo every ~5s
// Slow path: getmininginfo every ~5s
if (doSlowRefresh) {
try {
miningInfo = rpc_->call("getmininginfo");
@@ -607,16 +643,9 @@ void App::refreshMiningInfo()
} catch (const std::exception& e) {
DEBUG_LOGF("getMiningInfo error: %s\n", e.what());
}
try {
nodeInfo = rpc_->call("getinfo");
nodeOk = true;
} catch (const std::exception& e) {
DEBUG_LOGF("getInfo error: %s\n", e.what());
}
}
return [this, miningInfo, localHashrateJson, nodeInfo, miningOk, hashrateOk, nodeOk, daemonMemMb]() {
return [this, miningInfo, localHashrateJson, miningOk, hashrateOk, daemonMemMb]() {
try {
if (hashrateOk) {
state_.mining.localHashrate = localHashrateJson.get<double>();
@@ -640,18 +669,6 @@ void App::refreshMiningInfo()
state_.mining.chain = miningInfo["chain"].get<std::string>();
state_.last_mining_update = std::time(nullptr);
}
if (nodeOk) {
if (nodeInfo.contains("version"))
state_.daemon_version = nodeInfo["version"].get<int>();
if (nodeInfo.contains("protocolversion"))
state_.protocol_version = nodeInfo["protocolversion"].get<int>();
if (nodeInfo.contains("p2pport"))
state_.p2p_port = nodeInfo["p2pport"].get<int>();
if (nodeInfo.contains("longestchain"))
state_.longestchain = nodeInfo["longestchain"].get<int>();
if (nodeInfo.contains("notarized"))
state_.notarized = nodeInfo["notarized"].get<int>();
}
} catch (const std::exception& e) {
DEBUG_LOGF("[refreshMiningInfo] callback error: %s\n", e.what());
}
@@ -965,6 +982,7 @@ void App::createNewZAddress(std::function<void(const std::string&)> callback)
rpc_->z_getNewAddress([this, callback](const json& result) {
std::string addr = result.get<std::string>();
addresses_dirty_ = true;
refreshAddresses();
if (callback) callback(addr);
});
@@ -976,6 +994,7 @@ void App::createNewTAddress(std::function<void(const std::string&)> callback)
rpc_->getNewAddress([this, callback](const json& result) {
std::string addr = result.get<std::string>();
addresses_dirty_ = true;
refreshAddresses();
if (callback) callback(addr);
});
@@ -1206,7 +1225,11 @@ void App::sendTransaction(const std::string& from, const std::string& to,
} catch (const std::exception& e) {
result_str = e.what();
}
return [callback, ok, result_str]() {
return [this, callback, ok, result_str]() {
if (ok) {
// A send changes address balances — refresh on next cycle
addresses_dirty_ = true;
}
if (callback) callback(ok, result_str);
};
});