kernel: allow setting chainstate `dbcache`
What changed, and why it matters
This commit adds a new public API knob to the Bitcoin Core 'libbitcoinkernel' library so that programs using the kernel can choose how much memory to use for the chainstate database cache. It also enforces minimum and maximum size limits. There is no obvious security bug in the change; it is a normal feature addition. The only security-relevant aspect is that the new setting is now properly validated and applied, whereas before the cache size was hard-coded.
No immediate action required. Treat as a routine feature commit. Reviewers may want to confirm that MIN_DBCACHE_BYTES/MAX_DBCACHE_BYTES match the documented API comments and that the cache split in kernel::CacheSizes remains safe for very small or very large values.
Security signals we found
New configurable cache-size API with explicit min/max validation
Replaces hard-coded DEFAULT_KERNEL_CACHE with caller-supplied value
Adds unit tests for out-of-range rejection and 32-bit upper-bound rejection
Uses existing mutex (opts.m_mutex) when reading/writing the new field
Evidence from the diff
The patch introduces btck_chainstate_manager_options_set_database_cache_bytes() in the kernel C API. It stores a uint64_t cache size inside ChainstateManagerOptions, validates it against MIN_DBCACHE_BYTES and MAX_DBCACHE_BYTES, splits it via kernel::CacheSizes, applies the block-tree portion to m_blockman_options.block_tree_db_params.cache_bytes, and uses the remainder during node::LoadChainstate(). A C++ wrapper SetDatabaseCacheBytes() and unit tests for boundary values are added. The change replaces the previous fixed DEFAULT_KERNEL_CACHE path with a configurable one.
Changed components
src/kernel/bitcoinkernel.cppsrc/kernel/bitcoinkernel.hsrc/kernel/bitcoinkernel_wrapper.hsrc/test/kernel/test_kernel.cppInspect captured patch +41 / −1
diff --git a/src/kernel/bitcoinkernel.cpp b/src/kernel/bitcoinkernel.cpp
index 52090c44..d27e7e9d 100644
--- a/src/kernel/bitcoinkernel.cpp
+++ b/src/kernel/bitcoinkernel.cpp
@@ -455,6 +455,7 @@ struct ChainstateManagerOptions {
node::BlockManager::Options m_blockman_options GUARDED_BY(m_mutex);
std::shared_ptr<const Context> m_context;
node::ChainstateLoadOptions m_chainstate_load_options GUARDED_BY(m_mutex);
+ uint64_t m_db_cache_bytes GUARDED_BY(m_mutex){DEFAULT_KERNEL_CACHE};
ChainstateManagerOptions(const std::shared_ptr<const Context>& context, const fs::path& data_dir, const fs::path& blocks_dir)
: m_chainman_options{ChainstateManager::Options{
@@ -1031,6 +1032,20 @@ void btck_chainstate_manager_options_set_worker_threads_num(btck_ChainstateManag
btck_ChainstateManagerOptions::get(opts).m_chainman_options.worker_threads_num = worker_threads;
}
+int btck_chainstate_manager_options_set_database_cache_bytes(btck_ChainstateManagerOptions* chainman_opts, uint64_t database_cache_bytes)
+{
+ if (database_cache_bytes < MIN_DBCACHE_BYTES || database_cache_bytes > MAX_DBCACHE_BYTES) {
+ LogError("Failed to set database cache: size is outside the supported range.");
+ return -1;
+ }
+
+ auto& opts{btck_ChainstateManagerOptions::get(chainman_opts)};
+ LOCK(opts.m_mutex);
+ opts.m_db_cache_bytes = database_cache_bytes;
+ opts.m_blockman_options.block_tree_db_params.cache_bytes = kernel::CacheSizes{database_cache_bytes}.block_tree_db;
+ return 0;
+}
+
void btck_chainstate_manager_options_destroy(btck_ChainstateManagerOptions* options)
{
delete options;
@@ -1083,7 +1098,7 @@ btck_ChainstateManager* btck_chainstate_manager_create(
try {
const auto chainstate_load_opts{WITH_LOCK(opts.m_mutex, return opts.m_chainstate_load_options)};
- kernel::CacheSizes cache_sizes{DEFAULT_KERNEL_CACHE};
+ const kernel::CacheSizes cache_sizes{WITH_LOCK(opts.m_mutex, return opts.m_db_cache_bytes)};
auto [status, chainstate_err]{node::LoadChainstate(*chainman, cache_sizes, chainstate_load_opts)};
if (status != node::ChainstateLoadStatus::SUCCESS) {
LogError("Failed to load chain state from your data directory: %s", chainstate_err.original);
diff --git a/src/kernel/bitcoinkernel.h b/src/kernel/bitcoinkernel.h
index 86ef2e2c..f474a7ca 100644
--- a/src/kernel/bitcoinkernel.h
+++ b/src/kernel/bitcoinkernel.h
@@ -1195,6 +1195,22 @@ BITCOINKERNEL_API void btck_chainstate_manager_options_set_worker_threads_num(
btck_ChainstateManagerOptions* chainstate_manager_options,
int worker_threads) BITCOINKERNEL_ARG_NONNULL(1);
+/**
+ * @brief Set the total database cache used by the chainstate manager.
+ *
+ * The total cache is split internally between the block tree database,
+ * chainstate database, and in-memory coins cache. If this function is not
+ * called, the total cache defaults to 450 MiB.
+ *
+ * @param[in] chainstate_manager_options Non-null, options to be set.
+ * @param[in] database_cache_bytes The total database cache size in bytes. Values below 4 MiB are rejected.
+ * On 32-bit systems, values above 1 GiB are also rejected.
+ * @return 0 if the set was successful, non-zero if the set failed.
+ */
+BITCOINKERNEL_API int BITCOINKERNEL_WARN_UNUSED_RESULT btck_chainstate_manager_options_set_database_cache_bytes(
+ btck_ChainstateManagerOptions* chainstate_manager_options,
+ uint64_t database_cache_bytes) BITCOINKERNEL_ARG_NONNULL(1);
+
/**
* @brief Sets wipe db in the options. In combination with calling
* @ref btck_chainstate_manager_import_blocks this triggers either a full reindex,
diff --git a/src/kernel/bitcoinkernel_wrapper.h b/src/kernel/bitcoinkernel_wrapper.h
index 5f251d30..5dc203b4 100644
--- a/src/kernel/bitcoinkernel_wrapper.h
+++ b/src/kernel/bitcoinkernel_wrapper.h
@@ -1200,6 +1200,11 @@ public:
btck_chainstate_manager_options_set_worker_threads_num(get(), worker_threads);
}
+ bool SetDatabaseCacheBytes(uint64_t database_cache_bytes)
+ {
+ return btck_chainstate_manager_options_set_database_cache_bytes(get(), database_cache_bytes) == 0;
+ }
+
bool SetWipeDbs(bool wipe_block_tree, bool wipe_chainstate)
{
return btck_chainstate_manager_options_set_wipe_dbs(get(), wipe_block_tree, wipe_chainstate) == 0;
diff --git a/src/test/kernel/test_kernel.cpp b/src/test/kernel/test_kernel.cpp
index 927d2b16..83613dbb 100644
--- a/src/test/kernel/test_kernel.cpp
+++ b/src/test/kernel/test_kernel.cpp
@@ -4,6 +4,7 @@
#include <kernel/bitcoinkernel.h>
#include <kernel/bitcoinkernel_wrapper.h>
+#include <util/byte_units.h>
#include <util/fs.h>
#define BOOST_TEST_MODULE Bitcoin Kernel Test Suite
@@ -800,6 +801,9 @@ BOOST_AUTO_TEST_CASE(btck_chainman_tests)
ChainstateManagerOptions chainman_opts{context, PathToString(test_directory.m_directory), PathToString(test_directory.m_directory / "blocks")};
chainman_opts.SetWorkerThreads(4);
+ BOOST_CHECK(!chainman_opts.SetDatabaseCacheBytes(4_MiB - 1));
+ if constexpr (sizeof(void*) == 4) BOOST_CHECK(!chainman_opts.SetDatabaseCacheBytes(2_GiB));
+ BOOST_CHECK(chainman_opts.SetDatabaseCacheBytes(4_MiB));
BOOST_CHECK(!chainman_opts.SetWipeDbs(/*wipe_block_tree=*/true, /*wipe_chainstate=*/false));
BOOST_CHECK(chainman_opts.SetWipeDbs(/*wipe_block_tree=*/true, /*wipe_chainstate=*/true));
BOOST_CHECK(chainman_opts.SetWipeDbs(/*wipe_block_tree=*/false, /*wipe_chainstate=*/true));
Why this scored 20/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.