From a7b4350e2147e3699dcf3b4edafdf007ed6673b9 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sun, 28 Aug 2022 21:53:24 +0000 Subject: [PATCH 1/6] Revert "Use more specific path when including `memenv.h` header" This reverts commit f3b5c1e4522f13060e9ace2913203e7a6b2eb2d1. --- cmake/leveldb.cmake | 1 + src/dbwrapper.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/leveldb.cmake b/cmake/leveldb.cmake index 139c6a5b3a85c..d5c0960af00ad 100644 --- a/cmake/leveldb.cmake +++ b/cmake/leveldb.cmake @@ -76,6 +76,7 @@ target_include_directories(leveldb $ PUBLIC $ + $ ) add_library(nowarn_leveldb_interface INTERFACE) diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index 8fb366515aff0..66262b300b452 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include From 7b1aa1e53d1f4f4893e499be45dc74b3312d9507 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Thu, 3 Apr 2025 06:02:16 +0000 Subject: [PATCH 2/6] cmake: Add unsupported `WITH_SYSTEM_LEVELDB` option --- CMakeLists.txt | 6 ++ cmake/module/FindLevelDB.cmake | 117 +++++++++++++++++++++++++++++++++ src/CMakeLists.txt | 3 + 3 files changed, 126 insertions(+) create mode 100644 cmake/module/FindLevelDB.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index f9467a5612d8e..aac835b47c745 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,6 +101,12 @@ option(BUILD_UTIL "Build bitcoin-util executable." ${BUILD_TESTS}) option(BUILD_UTIL_CHAINSTATE "Build experimental bitcoin-chainstate executable." OFF) option(BUILD_KERNEL_LIB "Build experimental bitcoinkernel library." ${BUILD_UTIL_CHAINSTATE}) +option(WITH_SYSTEM_LEVELDB "Build with system LevelDB instead of embedded fork." OFF) +mark_as_advanced(WITH_SYSTEM_LEVELDB) +if(WITH_SYSTEM_LEVELDB) + find_package(LevelDB MODULE REQUIRED) +endif() # WITH_SYSTEM_LEVELDB + option(ENABLE_WALLET "Enable wallet." ON) option(WITH_SQLITE "Enable SQLite wallet support." ${ENABLE_WALLET}) if(WITH_SQLITE) diff --git a/cmake/module/FindLevelDB.cmake b/cmake/module/FindLevelDB.cmake new file mode 100644 index 0000000000000..fad518b4ee394 --- /dev/null +++ b/cmake/module/FindLevelDB.cmake @@ -0,0 +1,117 @@ +# Copyright (c) 2023-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit/. + +include(CheckSourceCompiles) +include(CMakePushCheckState) + +message(CHECK_START "Looking for system LevelDB") + +find_path(LevelDB_INCLUDE_DIR + NAMES leveldb/filter_policy.h + DOC "Path to LevelDB include directory (ie, the directory ABOVE leveldb/db.h)" +) +mark_as_advanced(LevelDB_INCLUDE_DIR) + +find_path(LevelDB_MemEnv_INCLUDE_DIR + NAMES memenv.h + HINTS "${LevelDB_INCLUDE_DIR}/leveldb/helpers" + DOC "Path to include directory for MemEnv LevelDB helper (ie, the directory with memenv.h)" +) +mark_as_advanced(LevelDB_MemEnv_INCLUDE_DIR) + +function(_try_leveldb_compile libs cachevar) + cmake_push_check_state(RESET) + list(APPEND CMAKE_REQUIRED_INCLUDES "${LevelDB_INCLUDE_DIR}") + list(APPEND CMAKE_REQUIRED_INCLUDES "${LevelDB_MemEnv_INCLUDE_DIR}") + list(APPEND CMAKE_REQUIRED_LIBRARIES "${libs}") + set(CMAKE_REQUIRED_QUIET 1) + check_source_compiles( + CXX + [[ + #include + #include + + int main() { + leveldb::Env *myenv = leveldb::NewMemEnv(leveldb::Env::Default()); + delete myenv; + } + ]] + "${cachevar}" + ) + cmake_pop_check_state() +endfunction() + +function(find_leveldb_libs release_type suffixes _LevelDB_lib_hint) + find_library("LevelDB_LIBRARY_${release_type}" + NAMES leveldb + HINTS "${_LevelDB_lib_hint}" + PATH_SUFFIXES "${suffixes}" + ) + mark_as_advanced("LevelDB_LIBRARY_${release_type}") + + _try_leveldb_compile("${LevelDB_LIBRARY_${release_type}}" "LevelDB_memenv_works_without_helper_lib_${release_type}") + if(LevelDB_memenv_works_without_helper_lib_${release_type}) + set("LevelDB_MemEnv_LIBRARY_${release_type}" "" CACHE STRING "") + set(LevelDB_MemEnv_FOUND ON CACHE INTERNAL "") + else() + find_library("LevelDB_MemEnv_LIBRARY_${release_type}" + NAMES memenv + HINTS "${_LevelDB_lib_hint}" + PATH_SUFFIXES "${suffixes}" + ) + + set(libs ${LevelDB_LIBRARY_${release_type}} ${LevelDB_MemEnv_LIBRARY_${release_type}}) + _try_leveldb_compile("${libs}" "LevelDB_memenv_works_with_helper_lib_${release_type}") + if(NOT LevelDB_memenv_works_with_helper_lib_${release_type}) + set(LevelDB_MemEnv_FOUND OFF CACHE INTERNAL "") + endif() + endif() + mark_as_advanced("LevelDB_MemEnv_LIBRARY_${release_type}") +endfunction() + +get_filename_component(_LevelDB_lib_hint "${LevelDB_INCLUDE_DIR}" DIRECTORY) + +find_leveldb_libs(RELEASE lib "${_LevelDB_lib_hint}") +find_leveldb_libs(DEBUG debug/lib "${_LevelDB_lib_hint}") + +unset(_LevelDB_lib_hint) + +include(SelectLibraryConfigurations) +select_library_configurations(LevelDB) +select_library_configurations(LevelDB_MemEnv) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LevelDB + REQUIRED_VARS LevelDB_LIBRARY LevelDB_INCLUDE_DIR LevelDB_MemEnv_INCLUDE_DIR LevelDB_MemEnv_FOUND +) + +if(LevelDB_FOUND) + message(CHECK_PASS "found") + if(NOT TARGET leveldb) + add_library(leveldb UNKNOWN IMPORTED) + set_target_properties(leveldb PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${LevelDB_INCLUDE_DIR};${LevelDB_MemEnv_INCLUDE_DIR}" + ) + if(LevelDB_LIBRARY_RELEASE) + set_property(TARGET leveldb APPEND PROPERTY + IMPORTED_CONFIGURATIONS RELEASE + ) + set_target_properties(leveldb PROPERTIES + IMPORTED_LOCATION_RELEASE "${LevelDB_LIBRARY_RELEASE}" + IMPORTED_LINK_INTERFACE_LIBRARIES_RELEASE "${LevelDB_MemEnv_LIBRARY_RELEASE}" + ) + endif() + if(LevelDB_LIBRARY_DEBUG) + set_property(TARGET leveldb APPEND PROPERTY + IMPORTED_CONFIGURATIONS DEBUG + ) + set_target_properties(leveldb PROPERTIES + IMPORTED_LOCATION_DEBUG "${LevelDB_LIBRARY_DEBUG}" + IMPORTED_LINK_INTERFACE_LIBRARIES_DEBUG "${LevelDB_MemEnv_LIBRARY_DEBUG}" + ) + endif() + endif() +else() + message(CHECK_FAIL "not found") +endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 41577b2ad6ddf..87c59b3f84c53 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -15,8 +15,11 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) # These need to be included before CMAKE_*_OUTPUT_DIRECTORY variables # are set, so output locations of subproject tests and libraries are # not overridden. +if(NOT WITH_SYSTEM_LEVELDB) include(../cmake/crc32c.cmake) include(../cmake/leveldb.cmake) +endif() # WITH_SYSTEM_LEVELDB + include(../cmake/minisketch.cmake) add_subdirectory(univalue) #============================= From 84ab8014f639db4ef29b268518ead25dc5939cea Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Thu, 12 Jul 2018 20:00:47 +0000 Subject: [PATCH 3/6] init: Sanity check LevelDB build/runtime versions --- src/dbwrapper.cpp | 19 +++++++++++++++++++ src/dbwrapper.h | 2 ++ src/kernel/checks.cpp | 5 +++++ 3 files changed, 26 insertions(+) diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index 66262b300b452..a88eb9d35631b 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -6,18 +6,21 @@ #include #include +#include #include #include #include #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -51,6 +54,22 @@ static void HandleError(const leveldb::Status& status) throw dbwrapper_error(errmsg); } +bool dbwrapper_SanityCheck() +{ + unsigned long header_version = (leveldb::kMajorVersion << 16) | leveldb::kMinorVersion; + unsigned long library_version = (leveldb_major_version() << 16) | leveldb_minor_version(); + + if (header_version != library_version) { + InitError(Untranslated(strprintf("Compiled with LevelDB %d.%d, but linked with LevelDB %d.%d (incompatible).", + leveldb::kMajorVersion, leveldb::kMinorVersion, + leveldb_major_version(), leveldb_minor_version() + ))); + return false; + } + + return true; +} + class CBitcoinLevelDBLogger : public leveldb::Logger { public: // This code is adapted from posix_logger.h, which is why it is using vsprintf. diff --git a/src/dbwrapper.h b/src/dbwrapper.h index dd5daa7a1fca1..6a368f6eeb986 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -20,6 +20,8 @@ #include #include +bool dbwrapper_SanityCheck(); + static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64; static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024; static const size_t DBWRAPPER_MAX_FILE_SIZE = 32 << 20; // 32 MiB diff --git a/src/kernel/checks.cpp b/src/kernel/checks.cpp index e4a13ee4cc2b3..22874b1a29a2a 100644 --- a/src/kernel/checks.cpp +++ b/src/kernel/checks.cpp @@ -4,6 +4,7 @@ #include +#include #include #include #include @@ -14,6 +15,10 @@ namespace kernel { util::Result SanityChecks(const Context&) { + if (!dbwrapper_SanityCheck()) { + return util::Error{Untranslated("Database sanity check failure. Aborting.")}; + } + if (!Random_SanityCheck()) { return util::Error{Untranslated("OS cryptographic RNG sanity check failure. Aborting.")}; } From f45f72cc15bea49fbec6607d42e9d5ad3fe7033d Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Wed, 3 Nov 2021 00:32:16 +0000 Subject: [PATCH 4/6] Use internal LevelDB test interface to bump LevelDB mmap limit up to 4096 like Bitcoin Core's fork No-op for embedded, but still done anyway Not applicable to Windows or 32-bit systems --- src/dbwrapper.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index a88eb9d35631b..f2b162846985d 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -70,6 +70,26 @@ bool dbwrapper_SanityCheck() return true; } +#ifndef WIN32 +namespace leveldb { +class EnvPosixTestHelper { + static void SetReadOnlyMMapLimit(int limit); +public: + static inline void SetReadOnlyMMapLimitForBitcoin(int limit) { SetReadOnlyMMapLimit(limit); } +}; +} + +class BitcoinLevelDBInit { +public: + BitcoinLevelDBInit() { + if (sizeof(void*) >= 8) { + leveldb::EnvPosixTestHelper::SetReadOnlyMMapLimitForBitcoin(4096); + } + } +}; +static BitcoinLevelDBInit g_bitcoin_leveldb_init; +#endif + class CBitcoinLevelDBLogger : public leveldb::Logger { public: // This code is adapted from posix_logger.h, which is why it is using vsprintf. From dd10cff7dd0aaeeab9c01cb80c31b9e5f4201e98 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Fri, 21 Jun 2024 18:13:19 +0000 Subject: [PATCH 5/6] QA/sanity_tests: Run dbwrapper_SanityCheck --- src/test/sanity_tests.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/sanity_tests.cpp b/src/test/sanity_tests.cpp index 68f82b760cc9a..607221277fcce 100644 --- a/src/test/sanity_tests.cpp +++ b/src/test/sanity_tests.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include @@ -11,6 +12,7 @@ BOOST_FIXTURE_TEST_SUITE(sanity_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(basic_sanity) { + BOOST_CHECK_MESSAGE(dbwrapper_SanityCheck() == true, "dbwrapper sanity test"); BOOST_CHECK_MESSAGE(ECC_InitSanityCheck() == true, "secp256k1 sanity test"); } From c8b6def2cf691040b13a02bde7b7c79c6904dc8b Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 25 Feb 2025 19:04:53 +0000 Subject: [PATCH 6/6] dbwrapper: Return util::Result for SanityCheck --- src/dbwrapper.cpp | 10 ++++------ src/dbwrapper.h | 3 ++- src/kernel/checks.cpp | 4 ++-- src/test/sanity_tests.cpp | 2 +- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index f2b162846985d..103adfc1d319e 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -6,7 +6,6 @@ #include #include -#include #include #include #include @@ -54,20 +53,19 @@ static void HandleError(const leveldb::Status& status) throw dbwrapper_error(errmsg); } -bool dbwrapper_SanityCheck() +util::Result dbwrapper_SanityCheck() { unsigned long header_version = (leveldb::kMajorVersion << 16) | leveldb::kMinorVersion; unsigned long library_version = (leveldb_major_version() << 16) | leveldb_minor_version(); if (header_version != library_version) { - InitError(Untranslated(strprintf("Compiled with LevelDB %d.%d, but linked with LevelDB %d.%d (incompatible).", + return util::Error{Untranslated(strprintf("Compiled with LevelDB %d.%d, but linked with LevelDB %d.%d (incompatible).", leveldb::kMajorVersion, leveldb::kMinorVersion, leveldb_major_version(), leveldb_minor_version() - ))); - return false; + ))}; } - return true; + return {}; } #ifndef WIN32 diff --git a/src/dbwrapper.h b/src/dbwrapper.h index 6a368f6eeb986..3bb933f4d69d7 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -20,7 +21,7 @@ #include #include -bool dbwrapper_SanityCheck(); +util::Result dbwrapper_SanityCheck(); static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64; static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024; diff --git a/src/kernel/checks.cpp b/src/kernel/checks.cpp index 22874b1a29a2a..7647f6abd4d14 100644 --- a/src/kernel/checks.cpp +++ b/src/kernel/checks.cpp @@ -15,8 +15,8 @@ namespace kernel { util::Result SanityChecks(const Context&) { - if (!dbwrapper_SanityCheck()) { - return util::Error{Untranslated("Database sanity check failure. Aborting.")}; + if (auto result{dbwrapper_SanityCheck()}; !result) { + return util::Error{util::ErrorString(result) + Untranslated("\nDatabase sanity check failure. Aborting.")}; } if (!Random_SanityCheck()) { diff --git a/src/test/sanity_tests.cpp b/src/test/sanity_tests.cpp index 607221277fcce..b82f36b1e272a 100644 --- a/src/test/sanity_tests.cpp +++ b/src/test/sanity_tests.cpp @@ -12,7 +12,7 @@ BOOST_FIXTURE_TEST_SUITE(sanity_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(basic_sanity) { - BOOST_CHECK_MESSAGE(dbwrapper_SanityCheck() == true, "dbwrapper sanity test"); + BOOST_CHECK_MESSAGE(dbwrapper_SanityCheck(), "dbwrapper sanity test"); BOOST_CHECK_MESSAGE(ECC_InitSanityCheck() == true, "secp256k1 sanity test"); }