From b10889d10752c5d5e4954af2959f7bdff47bd67c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C5=91rinc?= Date: Thu, 4 Jun 2026 19:42:00 +0200 Subject: [PATCH] coins: test chainstate flush baseline Add `CDBWrapper::GetProperty()` and expose it through `CCoinsViewDB::GetDBProperty()` so coins tests can inspect LevelDB runtime properties through the coins view. Use it in a coins DB flush baseline that records the LevelDB layout after flushing while keeping readback coverage for the flushed coin and best block. Co-authored-by: Andrew Toth --- src/dbwrapper.cpp | 9 +++++++-- src/dbwrapper.h | 3 +++ src/test/coins_tests.cpp | 23 +++++++++++++++++++++++ src/txdb.cpp | 5 +++++ src/txdb.h | 4 ++++ 5 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index 1d2b6f0d9a8..d51a347c627 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -301,11 +301,16 @@ void CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync) } } +std::optional CDBWrapper::GetProperty(const std::string& property) const +{ + if (std::string value; DBContext().pdb->GetProperty(property, &value)) return value; + return std::nullopt; +} + size_t CDBWrapper::DynamicMemoryUsage() const { - std::string memory; std::optional parsed; - if (!DBContext().pdb->GetProperty("leveldb.approximate-memory-usage", &memory) || !(parsed = ToIntegral(memory))) { + if (auto memory{GetProperty("leveldb.approximate-memory-usage")}; !memory || !(parsed = ToIntegral(*memory))) { LogDebug(BCLog::LEVELDB, "Failed to get approximate-memory-usage property\n"); return 0; } diff --git a/src/dbwrapper.h b/src/dbwrapper.h index edbe69cef14..a5f631162a9 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -258,6 +258,9 @@ public: void WriteBatch(CDBBatch& batch, bool fSync = false); + //! Return a LevelDB property value, if available. + std::optional GetProperty(const std::string& property) const; + // Get an estimate of LevelDB memory usage (in bytes). size_t DynamicMemoryUsage() const; diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 14ccb1c443c..847297e5148 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -1060,6 +1061,28 @@ BOOST_FIXTURE_TEST_CASE(ccoins_flush_behavior, FlushTest) } } +BOOST_FIXTURE_TEST_CASE(coins_db_leveldb_layout, FlushTest) +{ + auto level2_files{[](CCoinsViewDB& base) { + return *Assert(ToIntegral(*Assert(base.GetDBProperty("leveldb.num-files-at-level2")))); + }}; + const COutPoint outpoint{Txid::FromUint256(m_rng.rand256()), 0}; + const Coin coin{MakeCoin()}; + const uint256 block_hash{m_rng.rand256()}; + + CCoinsViewDB base{{.path = m_args.GetDataDirBase() / "coins_db_leveldb_layout", .cache_bytes = 1_MiB, .wipe_data = true}, {}}; + CCoinsViewCache cache{&base}; + + cache.EmplaceCoinInternalDANGER(COutPoint{outpoint}, Coin{coin}); + cache.SetBestBlock(block_hash); + cache.Sync(); + + BOOST_CHECK_EQUAL(level2_files(base), 0); + + BOOST_CHECK(*Assert(base.GetCoin(outpoint)) == coin); + BOOST_CHECK_EQUAL(base.GetBestBlock(), block_hash); +} + BOOST_AUTO_TEST_CASE(coins_resource_is_used) { CCoinsMapMemoryResource resource; diff --git a/src/txdb.cpp b/src/txdb.cpp index a41dfd1657a..7f45a7c0683 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -175,6 +175,11 @@ size_t CCoinsViewDB::EstimateSize() const return m_db->EstimateSize(DB_COIN, uint8_t(DB_COIN + 1)); } +std::optional CCoinsViewDB::GetDBProperty(const std::string& property) +{ + return m_db->GetProperty(property); +} + /** Specialization of CCoinsViewCursor to iterate over a CCoinsViewDB */ class CCoinsViewDBCursor: public CCoinsViewCursor { diff --git a/src/txdb.h b/src/txdb.h index b19b312a4b6..827b36f3fa6 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -17,6 +17,7 @@ #include #include #include +#include #include class COutPoint; @@ -54,6 +55,9 @@ public: //! Dynamically alter the underlying leveldb cache size. void ResizeCache(size_t new_cache_size) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + + //! Return an underlying LevelDB property value, if available. + std::optional GetDBProperty(const std::string& property); }; #endif // BITCOIN_TXDB_H