aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRussell Yanofsky <[email protected]>2020-08-04 16:40:31 -0400
committerRussell Yanofsky <[email protected]>2020-09-03 12:24:32 -0400
commitb5b414151af32e5a07b5757b64482d77519d77c0 (patch)
treec6149426f3c4e7c72507db59d59b62d2ecb774b6 /src
parentRemove WalletLocation class (diff)
downloaddiscoin-b5b414151af32e5a07b5757b64482d77519d77c0.tar.xz
discoin-b5b414151af32e5a07b5757b64482d77519d77c0.zip
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 https://github.com/bitcoin/bitcoin/pull/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.
Diffstat (limited to 'src')
-rw-r--r--src/wallet/bdb.cpp32
-rw-r--r--src/wallet/bdb.h9
-rw-r--r--src/wallet/db.h22
-rw-r--r--src/wallet/walletdb.cpp39
-rw-r--r--src/wallet/walletutil.cpp2
5 files changed, 103 insertions, 1 deletions
diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp
index 24eb2ee34..61463aaf5 100644
--- a/src/wallet/bdb.cpp
+++ b/src/wallet/bdb.cpp
@@ -824,3 +824,35 @@ std::unique_ptr<DatabaseBatch> BerkeleyDatabase::MakeBatch(const char* mode, boo
{
return MakeUnique<BerkeleyBatch>(*this, mode, flush_on_close);
}
+
+bool ExistsBerkeleyDatabase(const fs::path& path)
+{
+ fs::path env_directory;
+ std::string data_filename;
+ SplitWalletPath(path, env_directory, data_filename);
+ return IsBerkeleyBtree(env_directory / data_filename);
+}
+
+std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
+{
+ std::unique_ptr<BerkeleyDatabase> db;
+ {
+ LOCK(cs_db); // Lock env.m_databases until insert in BerkeleyDatabase constructor
+ std::string data_filename;
+ std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(path, data_filename);
+ if (env->m_databases.count(data_filename)) {
+ error = Untranslated(strprintf("Refusing to load database. Data file '%s' is already loaded.", (env->Directory() / data_filename).string()));
+ status = DatabaseStatus::FAILED_ALREADY_LOADED;
+ return nullptr;
+ }
+ db = MakeUnique<BerkeleyDatabase>(std::move(env), std::move(data_filename));
+ }
+
+ if (options.verify && !db->Verify(error)) {
+ status = DatabaseStatus::FAILED_VERIFY;
+ return nullptr;
+ }
+
+ status = DatabaseStatus::SUCCESS;
+ return db;
+}
diff --git a/src/wallet/bdb.h b/src/wallet/bdb.h
index 75546924e..82ad13664 100644
--- a/src/wallet/bdb.h
+++ b/src/wallet/bdb.h
@@ -90,6 +90,9 @@ std::shared_ptr<BerkeleyEnvironment> GetWalletEnv(const fs::path& wallet_path, s
/** Return whether a BDB wallet database is currently loaded. */
bool IsBDBWalletLoaded(const fs::path& wallet_path);
+/** Check format of database file */
+bool IsBerkeleyBtree(const fs::path& path);
+
class BerkeleyBatch;
/** An instance of this class represents one database.
@@ -224,4 +227,10 @@ public:
std::string BerkeleyDatabaseVersion();
+//! Check if Berkeley database exists at specified path.
+bool ExistsBerkeleyDatabase(const fs::path& path);
+
+//! Return object giving access to Berkeley database at specified path.
+std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
+
#endif // BITCOIN_WALLET_BDB_H
diff --git a/src/wallet/db.h b/src/wallet/db.h
index 0afaba5fd..f0f6f03c4 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -195,4 +195,26 @@ public:
std::unique_ptr<DatabaseBatch> MakeBatch(const char* mode = "r+", bool flush_on_close = true) override { return MakeUnique<DummyBatch>(); }
};
+enum class DatabaseFormat {
+ BERKELEY,
+};
+
+struct DatabaseOptions {
+ bool require_existing = false;
+ bool require_create = false;
+ bool verify = true;
+};
+
+enum class DatabaseStatus {
+ SUCCESS,
+ FAILED_BAD_PATH,
+ FAILED_BAD_FORMAT,
+ FAILED_ALREADY_LOADED,
+ FAILED_ALREADY_EXISTS,
+ FAILED_NOT_FOUND,
+ FAILED_VERIFY,
+};
+
+std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
+
#endif // BITCOIN_WALLET_DB_H
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 962ea66fa..23c4b6977 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -13,6 +13,8 @@
#include <util/bip32.h>
#include <util/system.h>
#include <util/time.h>
+#include <util/translation.h>
+#include <wallet/bdb.h>
#include <wallet/wallet.h>
#include <atomic>
@@ -993,6 +995,43 @@ bool WalletBatch::TxnAbort()
return m_batch->TxnAbort();
}
+std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
+{
+ bool exists;
+ try {
+ exists = fs::symlink_status(path).type() != fs::file_not_found;
+ } catch (const fs::filesystem_error& e) {
+ error = Untranslated(strprintf("Failed to access database path '%s': %s", path.string(), fsbridge::get_filesystem_error_message(e)));
+ status = DatabaseStatus::FAILED_BAD_PATH;
+ return nullptr;
+ }
+
+ Optional<DatabaseFormat> format;
+ if (exists) {
+ if (ExistsBerkeleyDatabase(path)) {
+ format = DatabaseFormat::BERKELEY;
+ }
+ } else if (options.require_existing) {
+ error = Untranslated(strprintf("Failed to load database path '%s'. Path does not exist.", path.string()));
+ status = DatabaseStatus::FAILED_NOT_FOUND;
+ return nullptr;
+ }
+
+ if (!format && options.require_existing) {
+ error = Untranslated(strprintf("Failed to load database path '%s'. Data is not in recognized format.", path.string()));
+ status = DatabaseStatus::FAILED_BAD_FORMAT;
+ return nullptr;
+ }
+
+ if (format && options.require_create) {
+ error = Untranslated(strprintf("Failed to create database path '%s'. Database already exists.", path.string()));
+ status = DatabaseStatus::FAILED_ALREADY_EXISTS;
+ return nullptr;
+ }
+
+ return MakeBerkeleyDatabase(path, options, status, error);
+}
+
bool IsWalletLoaded(const fs::path& wallet_path)
{
return IsBDBWalletLoaded(wallet_path);
diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp
index d6a8ee9e0..e4c72aed9 100644
--- a/src/wallet/walletutil.cpp
+++ b/src/wallet/walletutil.cpp
@@ -29,7 +29,7 @@ fs::path GetWalletDir()
return path;
}
-static bool IsBerkeleyBtree(const fs::path& path)
+bool IsBerkeleyBtree(const fs::path& path)
{
if (!fs::exists(path)) return false;