diff --git a/configure.ac b/configure.ac index f088309038..6687ee16d4 100644 --- a/configure.ac +++ b/configure.ac @@ -1227,6 +1227,68 @@ if test "$have_any_system" != "no"; then AC_DEFINE([HAVE_SYSTEM], [1], [Define to 1 if std::system or ::wsystem is available.]) fi +dnl Check for leveldb, only if explicitly requested +LEVELDB_CPPFLAGS= +LIBLEVELDB= +LIBMEMENV= +AC_ARG_WITH([system-leveldb], + [AS_HELP_STRING([--with-system-leveldb], + [Build with system LevelDB (default is no; DANGEROUS; NOT SUPPORTED)])], + [system_leveldb=$withval], + [system_leveldb=no] +) +if test x$system_leveldb != xno; then + LEVELDB_CPPFLAGS= + AC_CHECK_LIB([leveldb],[main],[ + LIBLEVELDB=-lleveldb + ],[ + AC_MSG_ERROR([leveldb library not found; using --with-system-leveldb is not supported anyway]) + ]) + AC_CHECK_HEADER([leveldb/filter_policy.h],[],[ + AC_MSG_ERROR([LevelDB headers not found; using --with-system-leveldb is not supported anyway]) + ]) + AC_CHECK_HEADER([leveldb/helpers/memenv.h],[ + AC_MSG_CHECKING([for memenv.h path]) + BITCOIN_SUBDIR_TO_INCLUDE([LEVELDB_CPPFLAGS],[leveldb/helpers/],[memenv]) + ],[ + AC_CHECK_HEADER([memenv.h],[],[ + AC_MSG_ERROR([LevelDB headers not found; using --with-system-leveldb is not supported anyway]) + ]) + ]) + + AC_MSG_CHECKING([library containing leveldb::NewMemEnv]) + TEMP_LIBS="$LIBS" + TEMP_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $LEVELDB_CPPFLAGS" + for searchlib in "" "-lmemenv" ERR; do + if test "x$searchlib" = "xERR"; then + AC_MSG_RESULT([no]) + AC_MSG_ERROR([LevelDB's memenv helper not found; using --with-system-leveldb is not supported anyway]) + fi + searchlib="$searchlib $LIBLEVELDB" + LIBS="$searchlib $TEMP_LIBS" + AC_LINK_IFELSE([AC_LANG_SOURCE([ + #include + #include + + int main() { + leveldb::Env *myenv = leveldb::NewMemEnv(leveldb::Env::Default()); + delete myenv; + } + ])],[ + AC_MSG_RESULT([$searchlib]) + LIBMEMENV="$searchlib" + break + ]) + done + LIBS="$TEMP_LIBS" + CPPFLAGS="$TEMP_CPPFLAGS" +fi +AM_CONDITIONAL([EMBEDDED_LEVELDB],[test x$system_leveldb = xno]) +AC_SUBST(LEVELDB_CPPFLAGS) +AC_SUBST(LIBLEVELDB) +AC_SUBST(LIBMEMENV) + dnl SUPPRESSED_CPPFLAGS=SUPPRESS_WARNINGS([$SOME_CPPFLAGS]) dnl Replace -I with -isystem in $SOME_CPPFLAGS to suppress warnings from dnl headers from its include directories and return the result. diff --git a/src/Makefile.am b/src/Makefile.am index dcdf0efd41..4f7fdb94d8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1133,8 +1133,10 @@ endif include Makefile.minisketch.include +if EMBEDDED_LEVELDB include Makefile.crc32c.include include Makefile.leveldb.include +endif include Makefile.test_util.include include Makefile.test_fuzz.include diff --git a/src/Makefile.leveldb.include b/src/Makefile.leveldb.include index bf14fe206b..1851afe9e1 100644 --- a/src/Makefile.leveldb.include +++ b/src/Makefile.leveldb.include @@ -8,11 +8,11 @@ LIBMEMENV_INT = leveldb/libmemenv.la noinst_LTLIBRARIES += $(LIBLEVELDB_INT) noinst_LTLIBRARIES += $(LIBMEMENV_INT) -LIBLEVELDB = $(LIBLEVELDB_INT) $(LIBCRC32C) -LIBMEMENV = $(LIBMEMENV_INT) +LIBLEVELDB += $(LIBLEVELDB_INT) $(LIBCRC32C) +LIBMEMENV += $(LIBMEMENV_INT) -LEVELDB_CPPFLAGS = LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include +LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/helpers/memenv LEVELDB_CPPFLAGS_INT = LEVELDB_CPPFLAGS_INT += -I$(srcdir)/leveldb diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index 775496e21b..421b588a8d 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -6,23 +6,26 @@ #include #include +#include #include #include #include #include #include #include +#include #include #include #include #include #include +#include #include #include #include #include -#include +#include #include #include #include @@ -51,6 +54,42 @@ 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; +} + +#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. diff --git a/src/dbwrapper.h b/src/dbwrapper.h index 63c2f99d2a..1face38484 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; diff --git a/src/kernel/checks.cpp b/src/kernel/checks.cpp index bf8a2ec74c..8ffa6c0e8f 100644 --- a/src/kernel/checks.cpp +++ b/src/kernel/checks.cpp @@ -4,6 +4,7 @@ #include +#include #include #include #include @@ -15,6 +16,10 @@ namespace kernel { util::Result SanityChecks(const Context&) { + if (!dbwrapper_SanityCheck()) { + return util::Error{Untranslated("Database sanity check failure. Aborting.")}; + } + if (!ECC_InitSanityCheck()) { return util::Error{Untranslated("Elliptic curve cryptography sanity check failure. Aborting.")}; } diff --git a/src/test/sanity_tests.cpp b/src/test/sanity_tests.cpp index 451bc99d44..938e68d9a8 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 #include @@ -12,6 +13,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"); BOOST_CHECK_MESSAGE(ChronoSanityCheck() == true, "chrono epoch test"); }