wallet, interfaces: Include database format in listWalletDir

This commit is contained in:
Ava Chow 2024-06-10 15:00:21 -04:00
parent 1873e4116f
commit 28fc562f26
8 changed files with 33 additions and 25 deletions

View file

@ -343,7 +343,7 @@ public:
virtual util::Result<WalletMigrationResult> migrateWallet(const std::string& name, const SecureString& passphrase) = 0; virtual util::Result<WalletMigrationResult> migrateWallet(const std::string& name, const SecureString& passphrase) = 0;
//! Return available wallets in wallet directory. //! Return available wallets in wallet directory.
virtual std::vector<std::string> listWalletDir() = 0; virtual std::vector<std::pair<std::string, std::string>> listWalletDir() = 0;
//! Return interfaces for accessing wallets (if any). //! Return interfaces for accessing wallets (if any).
virtual std::vector<std::unique_ptr<Wallet>> getWallets() = 0; virtual std::vector<std::unique_ptr<Wallet>> getWallets() = 0;

View file

@ -396,15 +396,15 @@ void BitcoinGUI::createActions()
connect(openAction, &QAction::triggered, this, &BitcoinGUI::openClicked); connect(openAction, &QAction::triggered, this, &BitcoinGUI::openClicked);
connect(m_open_wallet_menu, &QMenu::aboutToShow, [this] { connect(m_open_wallet_menu, &QMenu::aboutToShow, [this] {
m_open_wallet_menu->clear(); m_open_wallet_menu->clear();
for (const std::pair<const std::string, bool>& i : m_wallet_controller->listWalletDir()) { for (const auto& [path, info] : m_wallet_controller->listWalletDir()) {
const std::string& path = i.first; const auto& [loaded, _] = info;
QString name = path.empty() ? QString("["+tr("default wallet")+"]") : QString::fromStdString(path); QString name = path.empty() ? QString("["+tr("default wallet")+"]") : QString::fromStdString(path);
// An single ampersand in the menu item's text sets a shortcut for this item. // An single ampersand in the menu item's text sets a shortcut for this item.
// Single & are shown when && is in the string. So replace & with &&. // Single & are shown when && is in the string. So replace & with &&.
name.replace(QChar('&'), QString("&&")); name.replace(QChar('&'), QString("&&"));
QAction* action = m_open_wallet_menu->addAction(name); QAction* action = m_open_wallet_menu->addAction(name);
if (i.second) { if (loaded) {
// This wallet is already loaded // This wallet is already loaded
action->setEnabled(false); action->setEnabled(false);
continue; continue;

View file

@ -65,16 +65,16 @@ WalletController::~WalletController()
delete m_activity_worker; delete m_activity_worker;
} }
std::map<std::string, bool> WalletController::listWalletDir() const std::map<std::string, std::pair<bool, std::string>> WalletController::listWalletDir() const
{ {
QMutexLocker locker(&m_mutex); QMutexLocker locker(&m_mutex);
std::map<std::string, bool> wallets; std::map<std::string, std::pair<bool, std::string>> wallets;
for (const std::string& name : m_node.walletLoader().listWalletDir()) { for (const auto& [name, format] : m_node.walletLoader().listWalletDir()) {
wallets[name] = false; wallets[name] = std::make_pair(false, format);
} }
for (WalletModel* wallet_model : m_wallets) { for (WalletModel* wallet_model : m_wallets) {
auto it = wallets.find(wallet_model->wallet().getWalletName()); auto it = wallets.find(wallet_model->wallet().getWalletName());
if (it != wallets.end()) it->second = true; if (it != wallets.end()) it->second.first = true;
} }
return wallets; return wallets;
} }

View file

@ -61,7 +61,7 @@ public:
//! Returns all wallet names in the wallet dir mapped to whether the wallet //! Returns all wallet names in the wallet dir mapped to whether the wallet
//! is loaded. //! is loaded.
std::map<std::string, bool> listWalletDir() const; std::map<std::string, std::pair<bool, std::string>> listWalletDir() const;
void closeWallet(WalletModel* wallet_model, QWidget* parent = nullptr); void closeWallet(WalletModel* wallet_model, QWidget* parent = nullptr);
void closeAllWallets(QWidget* parent = nullptr); void closeAllWallets(QWidget* parent = nullptr);

View file

@ -19,9 +19,9 @@ namespace wallet {
bool operator<(BytePrefix a, Span<const std::byte> b) { return a.prefix < b.subspan(0, std::min(a.prefix.size(), b.size())); } bool operator<(BytePrefix a, Span<const std::byte> b) { return a.prefix < b.subspan(0, std::min(a.prefix.size(), b.size())); }
bool operator<(Span<const std::byte> a, BytePrefix b) { return a.subspan(0, std::min(a.size(), b.prefix.size())) < b.prefix; } bool operator<(Span<const std::byte> a, BytePrefix b) { return a.subspan(0, std::min(a.size(), b.prefix.size())) < b.prefix; }
std::vector<fs::path> ListDatabases(const fs::path& wallet_dir) std::vector<std::pair<fs::path, std::string>> ListDatabases(const fs::path& wallet_dir)
{ {
std::vector<fs::path> paths; std::vector<std::pair<fs::path, std::string>> paths;
std::error_code ec; std::error_code ec;
for (auto it = fs::recursive_directory_iterator(wallet_dir, ec); it != fs::recursive_directory_iterator(); it.increment(ec)) { for (auto it = fs::recursive_directory_iterator(wallet_dir, ec); it != fs::recursive_directory_iterator(); it.increment(ec)) {
@ -38,21 +38,29 @@ std::vector<fs::path> ListDatabases(const fs::path& wallet_dir)
try { try {
const fs::path path{it->path().lexically_relative(wallet_dir)}; const fs::path path{it->path().lexically_relative(wallet_dir)};
if (it->status().type() == fs::file_type::directory && if (it->status().type() == fs::file_type::directory) {
(IsBDBFile(BDBDataFile(it->path())) || IsSQLiteFile(SQLiteDataFile(it->path())))) { if (IsBDBFile(BDBDataFile(it->path()))) {
// Found a directory which contains wallet.dat btree file, add it as a wallet. // Found a directory which contains wallet.dat btree file, add it as a wallet with BERKELEY format.
paths.emplace_back(path); paths.emplace_back(path, "bdb");
} else if (IsSQLiteFile(SQLiteDataFile(it->path()))) {
// Found a directory which contains wallet.dat sqlite file, add it as a wallet with SQLITE format.
paths.emplace_back(path, "sqlite");
}
} else if (it.depth() == 0 && it->symlink_status().type() == fs::file_type::regular && it->path().extension() != ".bak") { } else if (it.depth() == 0 && it->symlink_status().type() == fs::file_type::regular && it->path().extension() != ".bak") {
if (it->path().filename() == "wallet.dat") { if (it->path().filename() == "wallet.dat") {
// Found top-level wallet.dat btree file, add top level directory "" // Found top-level wallet.dat file, add top level directory ""
// as a wallet. // as a wallet.
paths.emplace_back(); if (IsBDBFile(it->path())) {
paths.emplace_back(fs::path(), "bdb");
} else if (IsSQLiteFile(it->path())) {
paths.emplace_back(fs::path(), "sqlite");
}
} else if (IsBDBFile(it->path())) { } else if (IsBDBFile(it->path())) {
// Found top-level btree file not called wallet.dat. Current bitcoin // Found top-level btree file not called wallet.dat. Current bitcoin
// software will never create these files but will allow them to be // software will never create these files but will allow them to be
// opened in a shared database environment for backwards compatibility. // opened in a shared database environment for backwards compatibility.
// Add it to the list of available wallets. // Add it to the list of available wallets.
paths.emplace_back(path); paths.emplace_back(path, "bdb");
} }
} }
} catch (const std::exception& e) { } catch (const std::exception& e) {

View file

@ -216,7 +216,7 @@ enum class DatabaseStatus {
}; };
/** Recursively list database paths in directory. */ /** Recursively list database paths in directory. */
std::vector<fs::path> ListDatabases(const fs::path& path); std::vector<std::pair<fs::path, std::string>> ListDatabases(const fs::path& path);
void ReadDatabaseArgs(const ArgsManager& args, DatabaseOptions& options); void ReadDatabaseArgs(const ArgsManager& args, DatabaseOptions& options);
std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error); std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);

View file

@ -656,11 +656,11 @@ public:
{ {
return fs::PathToString(GetWalletDir()); return fs::PathToString(GetWalletDir());
} }
std::vector<std::string> listWalletDir() override std::vector<std::pair<std::string, std::string>> listWalletDir() override
{ {
std::vector<std::string> paths; std::vector<std::pair<std::string, std::string>> paths;
for (auto& path : ListDatabases(GetWalletDir())) { for (auto& [path, format] : ListDatabases(GetWalletDir())) {
paths.push_back(fs::PathToString(path)); paths.emplace_back(fs::PathToString(path), format);
} }
return paths; return paths;
} }

View file

@ -169,7 +169,7 @@ static RPCHelpMan listwalletdir()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{ {
UniValue wallets(UniValue::VARR); UniValue wallets(UniValue::VARR);
for (const auto& path : ListDatabases(GetWalletDir())) { for (const auto& [path, _] : ListDatabases(GetWalletDir())) {
UniValue wallet(UniValue::VOBJ); UniValue wallet(UniValue::VOBJ);
wallet.pushKV("name", path.utf8string()); wallet.pushKV("name", path.utf8string());
wallets.push_back(std::move(wallet)); wallets.push_back(std::move(wallet));