diff --git a/src/app.h b/src/app.h index 500ed7e..f6c7198 100644 --- a/src/app.h +++ b/src/app.h @@ -769,6 +769,7 @@ private: chat::ChatDatabase chat_db_; // persistent backing (seed-derived encryption at rest) bool chat_identity_provisioned_ = false; // identity set on the service this session bool chat_identity_fetch_in_flight_ = false; // a z_exportmnemonic worker job is pending + std::chrono::steady_clock::time_point chat_identity_retry_at_{}; // after a transient failure // Bumped by resetChatSession() on every wallet change; an in-flight identity fetch captures the // value at post time and its completion callback discards its (previous-wallet) secret if the id // no longer matches — so wallet A's seed can't be provisioned under wallet B via a stale job. @@ -1098,6 +1099,7 @@ private: bool seed_backup_loading_ = false; bool seed_backup_no_mnemonic_ = false; bool seed_backup_reminder_in_flight_ = false; // guards the one-time backup nudge probe + std::chrono::steady_clock::time_point seed_backup_reminder_retry_at_{}; // after an inconclusive probe bool large_wallet_checked_ = false; // gate: stat wallet.dat for the bloat nudge once per launch // Cached mnemonic status of the current wallet, driving the Migrate-to-seed button glow. Probed diff --git a/src/app_network.cpp b/src/app_network.cpp index bbad5ab..250b49f 100644 --- a/src/app_network.cpp +++ b/src/app_network.cpp @@ -3136,6 +3136,9 @@ void App::maybeProvisionChatIdentity() if (chat_service_.hasIdentity() || chat_identity_provisioned_ || chat_identity_fetch_in_flight_ || chat_identity_unavailable_) return; + // After a transient failure (connection blip, a busy node) wait before asking again: retrying on the + // next frame re-sent the request continuously. + if (std::chrono::steady_clock::now() < chat_identity_retry_at_) return; if (supportsLiteBackend()) { // Lite: the backend's `seed` command returns the 24-word mnemonic synchronously. @@ -3206,6 +3209,7 @@ void App::maybeProvisionChatIdentity() } chat_identity_fetch_in_flight_ = false; if (unavailable) chat_identity_unavailable_ = true; + if (transientFail) chat_identity_retry_at_ = std::chrono::steady_clock::now() + std::chrono::seconds(10); // Provision only on success AND while still unlocked: a lock (e.g. auto-lock) can // land during the blocking fetch, and provisioning then would unlock the chat DB + // load decrypted history while the wallet is locked. Leaving the flag cleared here @@ -4451,6 +4455,9 @@ void App::maybeRemindSeedBackup() if (!state_.connected || !state_.encryption_state_known) return; if (state_.isLocked()) return; // wait until unlocked to read it if (seed_backup_reminder_in_flight_) return; + // An inconclusive answer (an error other than "not derived from a mnemonic" — e.g. a daemon without + // the RPC, or a busy one) used to re-fire this probe on the very next frame, hammering the daemon. + if (std::chrono::steady_clock::now() < seed_backup_reminder_retry_at_) return; seed_backup_reminder_in_flight_ = true; exportSeedPhrase([this](bool ok, bool noMnemonic, const std::string& /*phrase*/, const std::string& /*error*/) { @@ -4460,6 +4467,8 @@ void App::maybeRemindSeedBackup() if (ok || noMnemonic) { settings_->setSeedBackupReminded(true); settings_->save(); + } else { + seed_backup_reminder_retry_at_ = std::chrono::steady_clock::now() + std::chrono::minutes(5); } if (ok) ui::Notifications::instance().info(TR("seed_backup_reminder"), 12.0f);