feat(wallet): per-wallet data isolation foundation (P1)
First phase of multi-wallet support: keep each wallet's data separate so loading
a different wallet no longer shows the previous one's data, and lay the metadata
groundwork for the wallet-files list.
- Address book scoped per wallet: AddressBookEntry gains a "scope" ("global" or a
wallet-identity hash); the Contacts tab shows global + current-wallet contacts
(App::activeWalletIdentityHash) with a "show in every wallet" toggle + globe
badge. Legacy entries migrate to "global". Scope-aware de-dup allows the same
address across different wallets.
- Wallet metadata index (data/wallet_index -> wallets.json): file-keyed cache of
balance / address count / identity / size / last-opened / synced-here, since
those can't be read off a wallet.dat without loading it. Populated on connect +
address refresh (change-detecting upsert). Plus an active_wallet_file setting
for the -wallet=<name> switch coming in P2.
Unit-tested (testAddressBookScope, testWalletIndex): migration, visibility filter,
scope-aware de-dup, upsert change-detection, save/reload round-trip.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
10
src/app.h
10
src/app.h
@@ -16,6 +16,7 @@
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include "data/transaction_history_cache.h"
|
||||
#include "data/address_book.h"
|
||||
#include "data/wallet_index.h"
|
||||
#include "data/wallet_state.h"
|
||||
#include "rpc/connection.h"
|
||||
#include "services/network_refresh_service.h"
|
||||
@@ -197,6 +198,10 @@ public:
|
||||
data::AddressBook& addressBook() { return address_book_; }
|
||||
const data::AddressBook& addressBook() const { return address_book_; }
|
||||
|
||||
// Hash of the active wallet's identity (derived from its address list), used to scope
|
||||
// per-wallet data (e.g. address-book contacts). Empty until addresses are known (pre-connect).
|
||||
std::string activeWalletIdentityHash() const;
|
||||
|
||||
// Connection state (convenience wrappers)
|
||||
bool isConnected() const { return state_.connected; }
|
||||
int getBlockHeight() const { return state_.sync.blocks; }
|
||||
@@ -555,6 +560,10 @@ private:
|
||||
void applyPendingSendBalanceDeltas(bool includeAggregateBalances);
|
||||
std::string transactionHistoryCacheWalletIdentity() const;
|
||||
bool ensureTransactionHistoryCacheUnlockedFor(const std::string& walletIdentity);
|
||||
// Record the active wallet's cached metadata (balance, address count, identity, size) into the
|
||||
// wallet index (wallets.json). Cheap + throttled: only writes when a value changed. markOpened
|
||||
// stamps last-opened + syncedHere (call once per connect).
|
||||
void updateWalletIndexForActiveWallet(bool markOpened);
|
||||
void unlockTransactionHistoryCacheWithPassphrase(const std::string& passphrase);
|
||||
// Shared main-thread continuations for a wallet unlock attempt, so the passphrase
|
||||
// and PIN paths cannot drift. applyUnlockFailure applies the escalating lockout
|
||||
@@ -965,6 +974,7 @@ private:
|
||||
std::unique_ptr<util::SecureVault> vault_;
|
||||
data::TransactionHistoryCache transaction_history_cache_;
|
||||
data::AddressBook address_book_; // shared contact store; loaded once in init(), self-saves on mutation
|
||||
data::WalletIndex wallet_index_; // per-wallet metadata cache (wallets.json); populated after each load
|
||||
std::string pending_transaction_history_cache_passphrase_;
|
||||
bool transaction_history_cache_loaded_ = false;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user