Skip to content

Commit b5b4141

Browse files
committed
wallet: Add MakeDatabase function
New function is not currently called but will be called in upcoming commits. It moves database path checking, and existence checking, and already-loaded checking, and verification into a single function so this logic does not need to be repeated all over higher level wallet code, and so higher level code does not need to change when SQLite support is added in bitcoin/bitcoin#19077. This also lets higher level wallet code make fewer assumptions about the contents of wallet directories. This commit just adds the new function and does not change behavior in any way.
1 parent 288b4ff commit b5b4141

File tree

5 files changed

+103
-1
lines changed

5 files changed

+103
-1
lines changed

src/wallet/bdb.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,3 +824,35 @@ std::unique_ptr<DatabaseBatch> BerkeleyDatabase::MakeBatch(const char* mode, boo
824824
{
825825
return MakeUnique<BerkeleyBatch>(*this, mode, flush_on_close);
826826
}
827+
828+
bool ExistsBerkeleyDatabase(const fs::path& path)
829+
{
830+
fs::path env_directory;
831+
std::string data_filename;
832+
SplitWalletPath(path, env_directory, data_filename);
833+
return IsBerkeleyBtree(env_directory / data_filename);
834+
}
835+
836+
std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
837+
{
838+
std::unique_ptr<BerkeleyDatabase> db;
839+
{
840+
LOCK(cs_db); // Lock env.m_databases until insert in BerkeleyDatabase constructor
841+
std::string data_filename;
842+
std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(path, data_filename);
843+
if (env->m_databases.count(data_filename)) {
844+
error = Untranslated(strprintf("Refusing to load database. Data file '%s' is already loaded.", (env->Directory() / data_filename).string()));
845+
status = DatabaseStatus::FAILED_ALREADY_LOADED;
846+
return nullptr;
847+
}
848+
db = MakeUnique<BerkeleyDatabase>(std::move(env), std::move(data_filename));
849+
}
850+
851+
if (options.verify && !db->Verify(error)) {
852+
status = DatabaseStatus::FAILED_VERIFY;
853+
return nullptr;
854+
}
855+
856+
status = DatabaseStatus::SUCCESS;
857+
return db;
858+
}

src/wallet/bdb.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ std::shared_ptr<BerkeleyEnvironment> GetWalletEnv(const fs::path& wallet_path, s
9090
/** Return whether a BDB wallet database is currently loaded. */
9191
bool IsBDBWalletLoaded(const fs::path& wallet_path);
9292

93+
/** Check format of database file */
94+
bool IsBerkeleyBtree(const fs::path& path);
95+
9396
class BerkeleyBatch;
9497

9598
/** An instance of this class represents one database.
@@ -224,4 +227,10 @@ class BerkeleyBatch : public DatabaseBatch
224227

225228
std::string BerkeleyDatabaseVersion();
226229

230+
//! Check if Berkeley database exists at specified path.
231+
bool ExistsBerkeleyDatabase(const fs::path& path);
232+
233+
//! Return object giving access to Berkeley database at specified path.
234+
std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
235+
227236
#endif // BITCOIN_WALLET_BDB_H

src/wallet/db.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,4 +195,26 @@ class DummyDatabase : public WalletDatabase
195195
std::unique_ptr<DatabaseBatch> MakeBatch(const char* mode = "r+", bool flush_on_close = true) override { return MakeUnique<DummyBatch>(); }
196196
};
197197

198+
enum class DatabaseFormat {
199+
BERKELEY,
200+
};
201+
202+
struct DatabaseOptions {
203+
bool require_existing = false;
204+
bool require_create = false;
205+
bool verify = true;
206+
};
207+
208+
enum class DatabaseStatus {
209+
SUCCESS,
210+
FAILED_BAD_PATH,
211+
FAILED_BAD_FORMAT,
212+
FAILED_ALREADY_LOADED,
213+
FAILED_ALREADY_EXISTS,
214+
FAILED_NOT_FOUND,
215+
FAILED_VERIFY,
216+
};
217+
218+
std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
219+
198220
#endif // BITCOIN_WALLET_DB_H

src/wallet/walletdb.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include <util/bip32.h>
1414
#include <util/system.h>
1515
#include <util/time.h>
16+
#include <util/translation.h>
17+
#include <wallet/bdb.h>
1618
#include <wallet/wallet.h>
1719

1820
#include <atomic>
@@ -993,6 +995,43 @@ bool WalletBatch::TxnAbort()
993995
return m_batch->TxnAbort();
994996
}
995997

998+
std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
999+
{
1000+
bool exists;
1001+
try {
1002+
exists = fs::symlink_status(path).type() != fs::file_not_found;
1003+
} catch (const fs::filesystem_error& e) {
1004+
error = Untranslated(strprintf("Failed to access database path '%s': %s", path.string(), fsbridge::get_filesystem_error_message(e)));
1005+
status = DatabaseStatus::FAILED_BAD_PATH;
1006+
return nullptr;
1007+
}
1008+
1009+
Optional<DatabaseFormat> format;
1010+
if (exists) {
1011+
if (ExistsBerkeleyDatabase(path)) {
1012+
format = DatabaseFormat::BERKELEY;
1013+
}
1014+
} else if (options.require_existing) {
1015+
error = Untranslated(strprintf("Failed to load database path '%s'. Path does not exist.", path.string()));
1016+
status = DatabaseStatus::FAILED_NOT_FOUND;
1017+
return nullptr;
1018+
}
1019+
1020+
if (!format && options.require_existing) {
1021+
error = Untranslated(strprintf("Failed to load database path '%s'. Data is not in recognized format.", path.string()));
1022+
status = DatabaseStatus::FAILED_BAD_FORMAT;
1023+
return nullptr;
1024+
}
1025+
1026+
if (format && options.require_create) {
1027+
error = Untranslated(strprintf("Failed to create database path '%s'. Database already exists.", path.string()));
1028+
status = DatabaseStatus::FAILED_ALREADY_EXISTS;
1029+
return nullptr;
1030+
}
1031+
1032+
return MakeBerkeleyDatabase(path, options, status, error);
1033+
}
1034+
9961035
bool IsWalletLoaded(const fs::path& wallet_path)
9971036
{
9981037
return IsBDBWalletLoaded(wallet_path);

src/wallet/walletutil.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ fs::path GetWalletDir()
2929
return path;
3030
}
3131

32-
static bool IsBerkeleyBtree(const fs::path& path)
32+
bool IsBerkeleyBtree(const fs::path& path)
3333
{
3434
if (!fs::exists(path)) return false;
3535

0 commit comments

Comments
 (0)