fix: FAQ CJK glyphs, outgoing-tx history, lite encryption, migrate & sync safety

Bug-report fixes plus adversarial-audit follow-ups. Bumps full 2.0.1->2.0.2 and
lite 1.1.0->1.1.1.

i18n / fonts:
- Rebuild the NotoSansCJK subset with the glyphs the FAQ back-fill introduced
  (什/么/门/做); Chinese FAQ titles rendered as "??" on zh (and ja/ko).

Transaction history (enumeration gaps):
- Surface outgoing shielded z->z sends via z_listsentbyaddress (listtransactions
  and z_listreceivedbyaddress never report them).
- Surface z->t deshields by parsing z_listsentbyaddress transparentSends (which
  z_viewtransaction does not expose); dedupe t->t against listtransactions.
- Key send-row dedup on address so equal-value multi-output sends aren't dropped.

Lite wallet (key safety):
- The async create/restore/open path the UI uses now applies the passphrase:
  encrypt a new/restored wallet, unlock an existing one. It previously discarded
  the passphrase, storing the seed/keys in PLAINTEXT (create/restore) or leaving
  an encrypted wallet locked (open).

Migrate-to-seed (fund safety):
- Persist a sweep-submitted marker at broadcast so a resumed migration can't treat
  a ~0 balance (an unconfirmed in-flight sweep) as an empty wallet and adopt (swap
  wallet.dat) before the sweep confirms; best-effort locate routes to the confirm gate.

Sync / threading:
- Gate isSynced() on a peer-derived tip (tip_known) so a peerless node isn't reported
  synced (Send against a stale balance); add a "no peers" status banner.
- Guard daemon_status_ with a mutex (monitor-thread write vs UI-thread read).

Tests: extends tests/test_phase4.cpp across all of the above; suite green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BwycPDQSfEKtrTS2uC4JeT
This commit is contained in:
2026-09-04 04:02:52 -05:00
co-authored by Claude Opus 4.8
parent f30fdc5ed1
commit fae8b20fb7
16 changed files with 646 additions and 34 deletions
+2
View File
@@ -267,6 +267,7 @@ bool Settings::load(const std::string& path)
loadScalar(j, "seed_migration_temp_dir", seed_migration_temp_dir_);
loadScalar(j, "seed_migration_sweep_txid", seed_migration_sweep_txid_);
loadScalar(j, "seed_migration_sweep_opid", seed_migration_sweep_opid_);
loadScalar(j, "seed_migration_sweep_submitted", seed_migration_sweep_submitted_);
loadScalar(j, "auto_lock_timeout", auto_lock_timeout_);
loadScalar(j, "unlock_duration", unlock_duration_);
loadScalar(j, "pin_enabled", pin_enabled_);
@@ -559,6 +560,7 @@ bool Settings::save(const std::string& path)
j["seed_migration_temp_dir"] = seed_migration_temp_dir_;
j["seed_migration_sweep_txid"] = seed_migration_sweep_txid_;
j["seed_migration_sweep_opid"] = seed_migration_sweep_opid_;
j["seed_migration_sweep_submitted"] = seed_migration_sweep_submitted_;
j["auto_lock_timeout"] = auto_lock_timeout_;
j["unlock_duration"] = unlock_duration_;
j["pin_enabled"] = pin_enabled_;
+7
View File
@@ -396,6 +396,12 @@ public:
// in the same write that persists the txid, so the txid always outranks it (see [[decideSeedMigrationResume]]).
std::string getSeedMigrationSweepOpid() const { return seed_migration_sweep_opid_; }
void setSeedMigrationSweepOpid(const std::string& v) { seed_migration_sweep_opid_ = v; }
// Set TRUE synchronously when a sweep is broadcast; survives the stale-opid resume fallback so the
// Sweep step knows a ~0 legacy balance may be an UNCONFIRMED in-flight sweep (funds not yet safe)
// and must NOT short-circuit to adopt/swap wallet.dat. Cleared on confirmed-adopt / reset / a
// failed submit. See [[decideSeedMigrationResume]] and App::renderSeedMigrationDialog (fund-safety).
bool getSeedMigrationSweepSubmitted() const { return seed_migration_sweep_submitted_; }
void setSeedMigrationSweepSubmitted(bool v) { seed_migration_sweep_submitted_ = v; }
// Security — auto-lock timeout (seconds; 0 = disabled)
int getAutoLockTimeout() const { return auto_lock_timeout_; }
@@ -640,6 +646,7 @@ private:
std::string seed_migration_temp_dir_;
std::string seed_migration_sweep_txid_;
std::string seed_migration_sweep_opid_;
bool seed_migration_sweep_submitted_ = false;
int auto_lock_timeout_ = 900; // 15 minutes
int unlock_duration_ = 600; // 10 minutes
bool pin_enabled_ = false;