From 6ace3e953f0864bd7818f040c59a1bc70aa47512 Mon Sep 17 00:00:00 2001 From: Ava Chow Date: Mon, 22 Apr 2024 15:21:58 -0400 Subject: [PATCH] bdb: Be able to make byteswapped databases Byteswapped databases make it easier to test opening and deserializing other endian databases. --- src/wallet/bdb.cpp | 16 +++++++++++++++- src/wallet/bdb.h | 3 +++ src/wallet/db.h | 1 + src/wallet/dump.cpp | 2 ++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp index 38cca32f80a..d82d8d45131 100644 --- a/src/wallet/bdb.cpp +++ b/src/wallet/bdb.cpp @@ -65,6 +65,8 @@ RecursiveMutex cs_db; std::map> g_dbenvs GUARDED_BY(cs_db); //!< Map from directory name to db environment. } // namespace +static constexpr auto REVERSE_BYTE_ORDER{std::endian::native == std::endian::little ? 4321 : 1234}; + bool WalletDatabaseFileId::operator==(const WalletDatabaseFileId& rhs) const { return memcmp(value, &rhs.value, sizeof(value)) == 0; @@ -300,7 +302,11 @@ static Span SpanFromDbt(const SafeDbt& dbt) } BerkeleyDatabase::BerkeleyDatabase(std::shared_ptr env, fs::path filename, const DatabaseOptions& options) : - WalletDatabase(), env(std::move(env)), m_filename(std::move(filename)), m_max_log_mb(options.max_log_mb) + WalletDatabase(), + env(std::move(env)), + m_byteswap(options.require_format == DatabaseFormat::BERKELEY_SWAP), + m_filename(std::move(filename)), + m_max_log_mb(options.max_log_mb) { auto inserted = this->env->m_databases.emplace(m_filename, std::ref(*this)); assert(inserted.second); @@ -389,6 +395,10 @@ void BerkeleyDatabase::Open() } } + if (m_byteswap) { + pdb_temp->set_lorder(REVERSE_BYTE_ORDER); + } + ret = pdb_temp->open(nullptr, // Txn pointer fMockDb ? nullptr : strFile.c_str(), // Filename fMockDb ? strFile.c_str() : "main", // Logical db name @@ -521,6 +531,10 @@ bool BerkeleyDatabase::Rewrite(const char* pszSkip) BerkeleyBatch db(*this, true); std::unique_ptr pdbCopy = std::make_unique(env->dbenv.get(), 0); + if (m_byteswap) { + pdbCopy->set_lorder(REVERSE_BYTE_ORDER); + } + int ret = pdbCopy->open(nullptr, // Txn pointer strFileRes.c_str(), // Filename "main", // Logical db name diff --git a/src/wallet/bdb.h b/src/wallet/bdb.h index 630630ebe01..af0c78f0d9e 100644 --- a/src/wallet/bdb.h +++ b/src/wallet/bdb.h @@ -147,6 +147,9 @@ public: /** Database pointer. This is initialized lazily and reset during flushes, so it can be null. */ std::unique_ptr m_db; + // Whether to byteswap + bool m_byteswap; + fs::path m_filename; int64_t m_max_log_mb; diff --git a/src/wallet/db.h b/src/wallet/db.h index 5751bba2e9e..b45076d10cb 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -184,6 +184,7 @@ enum class DatabaseFormat { BERKELEY, SQLITE, BERKELEY_RO, + BERKELEY_SWAP, }; struct DatabaseOptions { diff --git a/src/wallet/dump.cpp b/src/wallet/dump.cpp index 970830754dc..db2756e0ca8 100644 --- a/src/wallet/dump.cpp +++ b/src/wallet/dump.cpp @@ -186,6 +186,8 @@ bool CreateFromDump(const ArgsManager& args, const std::string& name, const fs:: data_format = DatabaseFormat::BERKELEY; } else if (file_format == "sqlite") { data_format = DatabaseFormat::SQLITE; + } else if (file_format == "bdb_swap") { + data_format = DatabaseFormat::BERKELEY_SWAP; } else { error = strprintf(_("Unknown wallet file format \"%s\" provided. Please provide one of \"bdb\" or \"sqlite\"."), file_format); return false;