feat(chat): pre-split note buffer for rapid sends + status + console logging

Each chat message is a shielded tx that spends a verified note, so a burst of
messages hit "insufficient verified funds" once the single note is spent. Add a
per-frame note-buffer coordinator (both variants) that keeps ~10 verified
spendable notes: it serializes sends through the one broadcast channel, counts
verified notes by block depth (lite) or a rate-limited z_listunspent scan
(full node), self-splits in the background to refill toward the target, and
queues overflow to drain as change matures — with honest Sent/Failed status
instead of the prior optimistic "Sent". Guardrails: single split in flight with
a watchdog, cooldown, and session-generation guards so a wallet switch can't
drain another wallet's queue. Surface a "Chat buffer: N/10 ready" indicator in
the status bar while the Chat tab is active, and route chat diagnostics through
the console on both variants (the full-node console now drains the shared ring).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-20 22:00:00 -05:00
parent 4471f54842
commit b0a4333cdf
5 changed files with 591 additions and 46 deletions

View File

@@ -29,6 +29,10 @@ namespace ui {
using namespace material;
// Classifies a diagnostics line into a console channel (defined below in an anonymous namespace); both
// executors drain the same LiteDiagnostics ring, so declare it up front for the full-node drain.
namespace { ConsoleChannel liteLogChannel(const std::string& line); }
// ============================================================================
// FullNodeConsoleExecutor
// ============================================================================
@@ -173,6 +177,25 @@ void FullNodeConsoleExecutor::pollLogLines(const ConsoleAddLineFn& add)
} else {
last_xmrig_output_size_ = 0; // reset so we get fresh output when it restarts
}
// Chat diagnostics ring: chat code logs via wallet::liteLog on both variants (send lifecycle, the
// 0-conf harvest, the note buffer). Surface those lines here as App messages so the full-node console
// shows chat activity too. Same generation-cursor drain the lite console uses.
{
auto& diag = wallet::LiteDiagnostics::instance();
const std::uint64_t gen = diag.generation();
if (gen != diag_gen_) {
const auto snap = diag.snapshot();
std::size_t startIdx = 0;
if (diag_gen_ != static_cast<std::uint64_t>(-1)) {
const std::uint64_t added = gen - diag_gen_;
startIdx = (added >= snap.size()) ? 0 : snap.size() - static_cast<std::size_t>(added);
}
for (std::size_t i = startIdx; i < snap.size(); ++i)
add(snap[i], liteLogChannel(snap[i]));
diag_gen_ = gen;
}
}
}
void FullNodeConsoleExecutor::printHelp(const ConsoleAddLineFn& add)

View File

@@ -113,6 +113,9 @@ private:
bool last_rpc_connected_ = false;
std::deque<std::pair<std::string, bool>> results_; // {text, isError}
std::mutex results_mutex_;
// Chat diagnostics ring cursor: chat code logs via wallet::liteLog on BOTH variants, so the full-node
// console surfaces those lines (as App messages) too — mirrors LiteConsoleExecutor's diag drain.
std::uint64_t diag_gen_ = static_cast<std::uint64_t>(-1);
};
// ── Lite: diagnostics ring + backend console command ─────────────────────────