fix(resilience,perf): gate send on a known tip, surface dropped/stale txs, advance cached confs, memoize explorer
Backlog mediums (display/gating/caching only — no send/sweep/encrypt call or args changed): Resilience: - Gate Send/Review on a KNOWN peer-derived tip (SyncInfo::sendTipReady): a fresh reconnect or peerless node has tip_known=false, so its local height isn't a trustworthy network tip — sending is disabled with a clear tooltip until it is. Lite is exempt (its own sync gate). The z_sendmany call is untouched. - History now shows "Dropped" for a conflicted tx (confirmations < 0) and "Expired?" for one unconfirmed > 1h, instead of "Pending" forever (new TransactionInfo::isConflicted/isStalePending; the tab inlines the check on its DisplayTx fields). - A cached z_viewtransaction row's confirmations now advance by the blocks mined since it was sampled (observed_height), instead of freezing at the cached value; never goes backwards; pending (0) isn't extrapolated. Performance: - Explorer block list uses loadRangeCached() (memoized on the cache revision) instead of loadRange(), so it only hits SQLite after the cache changes, not every frame. Tests: testResilienceMediums (tip gate, confirmations-advance, dropped/stale predicates) + loadRangeCached memoization in testExplorerBlockCache (isolated on its own cache). Held: Overview/Balance per-frame list cache, peers clippers, off-thread tx-history cache load (larger refactors). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -75,6 +75,13 @@ struct TransactionInfo {
|
||||
std::string getTypeDisplay() const;
|
||||
bool isConfirmed() const { return confirmations >= 1; }
|
||||
bool isMature() const { return confirmations >= 100; }
|
||||
// gettransaction reports confirmations < 0 for a tx conflicted with the chain (double-spent / reorged out).
|
||||
bool isConflicted() const { return confirmations < 0; }
|
||||
// Unconfirmed for longer than maxAgeSec since the wallet first saw it: most likely dropped from the
|
||||
// mempool or expired. A display heuristic only (timestamp 0 = unknown -> never flagged).
|
||||
bool isStalePending(int64_t now, int64_t maxAgeSec = 3600) const {
|
||||
return confirmations == 0 && timestamp > 0 && now - timestamp > maxAgeSec;
|
||||
}
|
||||
};
|
||||
|
||||
// Exact field-wise equality: decides whether a refreshed list really differs. `amount` is compared
|
||||
@@ -198,6 +205,11 @@ struct SyncInfo {
|
||||
bool tip_known = false;
|
||||
|
||||
bool isSynced() const { return tip_known && !syncing && blocks > 0 && blocks >= headers - 2; }
|
||||
|
||||
// Send precondition: the wallet is caught up to a KNOWN peer-derived tip. A fresh (re)connect or a
|
||||
// peerless node has tip_known == false, so its local height can't be trusted as the network tip.
|
||||
// The lite backend never populates tip_known, so lite is exempt (it has its own sync gate).
|
||||
bool sendTipReady(bool liteBuild) const { return liteBuild || (tip_known && !syncing && blocks > 0); }
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user