feat(wallets): show created date + sort the wallet list
Parse the earliest keymeta nCreateTime out of the wallet.dat btree (the daemon's
"wallet birthday") and surface it in each row's metadata line ("created Aug 2025").
Add a sort control above the list — Date created / Address count / Transaction
count / Wallet size, with an ascending/descending toggle (descending default:
newest / most / largest first). Sorting reorders a display-index array
(s_order) rather than s_rows, so the async, index-aligned probe batch is
untouched; sort keys read a single frame-consistent snapshot of the probe
results. Address count prefers the authoritative cached index value, else the
btree key count.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -260,6 +260,14 @@ void I18n::loadBuiltinEnglish()
|
||||
strings_["wallets_col_addresses"] = "Addresses";
|
||||
strings_["wallets_col_txs"] = "txs";
|
||||
strings_["wallets_col_keys"] = "keys";
|
||||
strings_["wallets_created"] = "created";
|
||||
strings_["wallets_sort_by"] = "Sort:";
|
||||
strings_["wallets_sort_created"] = "Date created";
|
||||
strings_["wallets_sort_addresses"] = "Address count";
|
||||
strings_["wallets_sort_txs"] = "Transaction count";
|
||||
strings_["wallets_sort_size"] = "Wallet size";
|
||||
strings_["wallets_sort_asc"] = "Ascending (oldest / fewest / smallest first)";
|
||||
strings_["wallets_sort_desc"] = "Descending (newest / most / largest first)";
|
||||
strings_["wallets_col_balance"] = "Balance";
|
||||
strings_["wallets_col_opened"] = "Last opened";
|
||||
strings_["wallets_current"] = "current";
|
||||
|
||||
@@ -135,6 +135,7 @@ struct WalletBtreeStats {
|
||||
int shieldedKeys = 0; ///< zkey + czkey + sapzkey + csapzkey (≈ shielded addresses)
|
||||
int addressBook = 0; ///< name records (labeled/received addresses)
|
||||
int txCount = 0; ///< tx records (wallet transactions)
|
||||
long long createdEpoch = 0; ///< earliest keymeta nCreateTime (wallet birthday); 0 = unknown
|
||||
bool encrypted = false; ///< saw an mkey record
|
||||
bool hdSeed = false; ///< saw hdseed/chdseed/hdchain
|
||||
std::size_t bytesRead = 0; ///< bytes actually read (for budgeting)
|
||||
@@ -275,7 +276,8 @@ inline WalletBtreeStats parseWalletBtree(const std::string& path,
|
||||
if (aborted) return st;
|
||||
if (subRoots.empty()) subRoots.push_back(root); // single-database file
|
||||
|
||||
auto countKey = [&](const unsigned char* kp, uint32_t kl) {
|
||||
auto countRecord = [&](const unsigned char* kp, uint32_t kl,
|
||||
const unsigned char* dp, uint32_t dl, uint8_t dtype) {
|
||||
const uint32_t nlen = kp[0]; // CompactSize length of the type string
|
||||
if (nlen < 2 || nlen > 20 || 1u + nlen > kl) return;
|
||||
const char* nm = reinterpret_cast<const char*>(kp + 1);
|
||||
@@ -286,9 +288,21 @@ inline WalletBtreeStats parseWalletBtree(const std::string& path,
|
||||
else if (is("tx")) st.txCount++;
|
||||
else if (is("mkey")) st.encrypted = true;
|
||||
else if (is("hdseed") || is("chdseed") || is("hdchain")) st.hdSeed = true;
|
||||
else if (is("keymeta")) {
|
||||
// CKeyMetadata data = nVersion(int32) + nCreateTime(int64) + …, all little-endian (Bitcoin
|
||||
// serialization). The earliest non-zero nCreateTime is the wallet birthday (daemon's
|
||||
// nTimeFirstKey). B_KEYDATA(1) only; overflow values aren't inline.
|
||||
if (dtype == B_KEYDATA && dp && dl >= 12) {
|
||||
long long t = 0;
|
||||
for (int b = 0; b < 8; ++b) t |= static_cast<long long>(dp[4 + b]) << (8 * b);
|
||||
if (t > 0 && (st.createdEpoch == 0 || t < st.createdEpoch)) st.createdEpoch = t;
|
||||
}
|
||||
}
|
||||
};
|
||||
for (const uint32_t sr : subRoots) {
|
||||
traverse(sr, [&](const unsigned char* kp, uint32_t kl, const unsigned char*, uint32_t, uint8_t) { countKey(kp, kl); });
|
||||
traverse(sr, [&](const unsigned char* kp, uint32_t kl, const unsigned char* dp, uint32_t dl, uint8_t dt) {
|
||||
countRecord(kp, kl, dp, dl, dt);
|
||||
});
|
||||
if (aborted) return st;
|
||||
}
|
||||
st.parsed = true;
|
||||
|
||||
Reference in New Issue
Block a user