fix(wallet): retire tracked sends that only paid the wallet itself
A send stays tracked until z_viewtransaction shows an outgoing output. Shields, merges/consolidations and chat note splits pay only the wallet itself, so they never showed one. They stayed tracked for the whole session and forced a full history refresh past the scan throttle on every tab. - A tracked send whose view has no outgoing output is retired once it is mined (1+ confirmations) or conflicted. - Tracked sends are enriched first, and reaching the per-cycle view cap no longer ends the loop, so the cap can't starve them. - Backstop: a tracked send still unsettled 20 blocks after it was added (expired, dropped from the mempool) stops being tracked. - Tracked sends are cleared on disconnect: they belong to that connection's wallet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -811,6 +811,10 @@ void App::onDisconnected(const std::string& reason)
|
||||
|
||||
// Clear RPC result caches
|
||||
viewtx_cache_.clear();
|
||||
// Tracked sends belong to this connection's wallet: kept across a switch/adopt they made
|
||||
// z_viewtransaction fail on the next wallet and left phantom pending "send" rows in its History.
|
||||
send_txids_.clear();
|
||||
send_txid_heights_.clear();
|
||||
confirmed_tx_cache_.clear();
|
||||
confirmed_tx_ids_.clear();
|
||||
confirmed_cache_block_ = -1;
|
||||
@@ -2161,6 +2165,7 @@ void App::refreshTransactionData()
|
||||
}
|
||||
NetworkRefreshService::applyTransactionRefreshResult(
|
||||
state_, cacheUpdate, std::move(result), std::time(nullptr));
|
||||
pruneTrackedSendTxids();
|
||||
shielded_history_scan_heights_ = std::move(shieldedScanHeights);
|
||||
storeTransactionHistoryCacheIfAvailable();
|
||||
shielded_history_scan_cursor_ = nextShieldedScanStartIndex;
|
||||
@@ -2175,6 +2180,30 @@ void App::refreshTransactionData()
|
||||
network_refresh_.resetTxAge();
|
||||
}
|
||||
|
||||
// Backstop for tracked sends that never settle (expired or dropped from the mempool, an RPC error, a
|
||||
// txid the wallet can't view): stop tracking after kTrackedSendTtlBlocks, since every tracked id keeps
|
||||
// forcing full history refreshes past the scan throttle. Anything that does confirm later is still
|
||||
// found and enriched by the untracked history sweep (z_listsentbyaddress).
|
||||
void App::pruneTrackedSendTxids()
|
||||
{
|
||||
const int tip = state_.sync.blocks;
|
||||
for (auto it = send_txid_heights_.begin(); it != send_txid_heights_.end();) {
|
||||
if (!send_txids_.count(it->first)) { // already resolved by a refresh
|
||||
it = send_txid_heights_.erase(it);
|
||||
continue;
|
||||
}
|
||||
if (it->second <= 0 && tip > 0) it->second = tip; // added before the tip was known
|
||||
if (tip > 0 && it->second > 0 && tip - it->second > kTrackedSendTtlBlocks) {
|
||||
DEBUG_LOGF("[tx] stop tracking send %s: unsettled after %d blocks\n",
|
||||
it->first.c_str(), tip - it->second);
|
||||
send_txids_.erase(it->first);
|
||||
it = send_txid_heights_.erase(it);
|
||||
continue;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void App::refreshRecentTransactionData()
|
||||
{
|
||||
if (!worker_ || !rpc_ || !state_.connected) return;
|
||||
|
||||
Reference in New Issue
Block a user