kernel: Add import blocks function to C header
What changed, and why it matters
This commit adds a new public function to Bitcoin Core's kernel library that lets callers import block files or trigger a reindex. It is a feature addition that exposes existing internal reindex/import logic through a C API. There is no direct evidence in the commit that it fixes a security bug; it appears to be ordinary API expansion for the libbitcoinkernel project.
Treat as a routine feature commit. If deploying libbitcoinkernel, review callers of btck_chainstate_manager_import_blocks for path injection risks and ensure the host application restricts file paths appropriately. No urgent patch action is indicated by this commit alone.
Security signals we found
New C API exposes filesystem path input to block import/reindex logic
Path strings are constructed from raw pointer + length pairs without visible sanitization
Function is exported as BITCOINKERNEL_API and therefore becomes part of the library's attack surface
No security-relevant commit message or changelog language present
Evidence from the diff
The patch introduces btck_chainstate_manager_import_blocks() in src/kernel/bitcoinkernel.cpp/h and a C++ wrapper ImportBlocks() in bitcoinkernel_wrapper.h. The function forwards to node::ImportBlocks() with a vector of fs::path built from caller-supplied path strings and lengths. It also updates documentation for the wipe-db options and adds two unit-test calls that exercise the new wrapper with empty and single-file path lists. No input validation beyond null checks is visible, and the existing ImportBlocks implementation is unchanged.
Changed components
src/kernel/bitcoinkernel.cppsrc/kernel/bitcoinkernel.hsrc/kernel/bitcoinkernel_wrapper.hsrc/test/kernel/test_kernel.cpplibbitcoinkernel C APIInspect captured patch +58 / −1
diff --git a/src/kernel/bitcoinkernel.cpp b/src/kernel/bitcoinkernel.cpp
index 5203221d..0c5d811d 100644
--- a/src/kernel/bitcoinkernel.cpp
+++ b/src/kernel/bitcoinkernel.cpp
@@ -795,6 +795,24 @@ void btck_chainstate_manager_destroy(btck_ChainstateManager* chainman)
delete chainman;
}
+int btck_chainstate_manager_import_blocks(btck_ChainstateManager* chainman, const char** block_file_paths_data, size_t* block_file_paths_lens, size_t block_file_paths_data_len)
+{
+ try {
+ std::vector<fs::path> import_files;
+ import_files.reserve(block_file_paths_data_len);
+ for (uint32_t i = 0; i < block_file_paths_data_len; i++) {
+ if (block_file_paths_data[i] != nullptr) {
+ import_files.emplace_back(std::string{block_file_paths_data[i], block_file_paths_lens[i]}.c_str());
+ }
+ }
+ node::ImportBlocks(*btck_ChainstateManager::get(chainman).m_chainman, import_files);
+ } catch (const std::exception& e) {
+ LogError("Failed to import blocks: %s", e.what());
+ return -1;
+ }
+ return 0;
+}
+
btck_Block* btck_block_create(const void* raw_block, size_t raw_block_length)
{
auto block{std::make_shared<CBlock>()};
diff --git a/src/kernel/bitcoinkernel.h b/src/kernel/bitcoinkernel.h
index c7c51ae4..651c54c4 100644
--- a/src/kernel/bitcoinkernel.h
+++ b/src/kernel/bitcoinkernel.h
@@ -747,7 +747,9 @@ BITCOINKERNEL_API void btck_chainstate_manager_options_set_worker_threads_num(
int worker_threads) BITCOINKERNEL_ARG_NONNULL(1);
/**
- * @brief Sets wipe db in the options.
+ * @brief Sets wipe db in the options. In combination with calling
+ * @ref btck_chainstate_manager_import_blocks this triggers either a full reindex,
+ * or a reindex of just the chainstate database.
*
* @param[in] chainstate_manager_options Non-null, created by @ref btck_chainstate_manager_options_create.
* @param[in] wipe_block_tree_db Set wipe block tree db. Should only be 1 if wipe_chainstate_db is 1 too.
@@ -802,6 +804,22 @@ BITCOINKERNEL_API void btck_chainstate_manager_options_destroy(btck_ChainstateMa
BITCOINKERNEL_API btck_ChainstateManager* BITCOINKERNEL_WARN_UNUSED_RESULT btck_chainstate_manager_create(
const btck_ChainstateManagerOptions* chainstate_manager_options) BITCOINKERNEL_ARG_NONNULL(1);
+/**
+ * @brief Triggers the start of a reindex if the wipe options were previously
+ * set for the chainstate manager. Can also import an array of existing block
+ * files selected by the user.
+ *
+ * @param[in] chainstate_manager Non-null.
+ * @param[in] block_file_paths_data Nullable, array of block files described by their full filesystem paths.
+ * @param[in] block_file_paths_lens Nullable, array containing the lengths of each of the paths.
+ * @param[in] block_file_paths_data_len Length of the block_file_paths_data and block_file_paths_len arrays.
+ * @return 0 if the import blocks call was completed successfully, non-zero otherwise.
+ */
+BITCOINKERNEL_API int BITCOINKERNEL_WARN_UNUSED_RESULT btck_chainstate_manager_import_blocks(
+ btck_ChainstateManager* chainstate_manager,
+ const char** block_file_paths_data, size_t* block_file_paths_lens,
+ size_t block_file_paths_data_len) BITCOINKERNEL_ARG_NONNULL(1);
+
/**
* @brief Process and validate the passed in block with the chainstate
* manager. Processing first does checks on the block, and if these passed,
diff --git a/src/kernel/bitcoinkernel_wrapper.h b/src/kernel/bitcoinkernel_wrapper.h
index c3b3e690..ff16f5bc 100644
--- a/src/kernel/bitcoinkernel_wrapper.h
+++ b/src/kernel/bitcoinkernel_wrapper.h
@@ -690,6 +690,20 @@ public:
{
}
+ bool ImportBlocks(const std::span<const std::string> paths)
+ {
+ std::vector<const char*> c_paths;
+ std::vector<size_t> c_paths_lens;
+ c_paths.reserve(paths.size());
+ c_paths_lens.reserve(paths.size());
+ for (const auto& path : paths) {
+ c_paths.push_back(path.c_str());
+ c_paths_lens.push_back(path.length());
+ }
+
+ return btck_chainstate_manager_import_blocks(get(), c_paths.data(), c_paths_lens.data(), c_paths.size()) == 0;
+ }
+
bool ProcessBlock(const Block& block, bool* new_block)
{
int _new_block;
diff --git a/src/test/kernel/test_kernel.cpp b/src/test/kernel/test_kernel.cpp
index 553d68f5..128f3f49 100644
--- a/src/test/kernel/test_kernel.cpp
+++ b/src/test/kernel/test_kernel.cpp
@@ -552,6 +552,9 @@ void chainman_reindex_test(TestDirectory& test_directory)
auto notifications{std::make_shared<TestKernelNotifications>()};
auto context{create_context(notifications, ChainType::MAINNET)};
auto chainman{create_chainman(test_directory, true, false, false, false, context)};
+
+ std::vector<std::string> import_files;
+ BOOST_CHECK(chainman->ImportBlocks(import_files));
}
void chainman_reindex_chainstate_test(TestDirectory& test_directory)
@@ -559,6 +562,10 @@ void chainman_reindex_chainstate_test(TestDirectory& test_directory)
auto notifications{std::make_shared<TestKernelNotifications>()};
auto context{create_context(notifications, ChainType::MAINNET)};
auto chainman{create_chainman(test_directory, false, true, false, false, context)};
+
+ std::vector<std::string> import_files;
+ import_files.push_back((test_directory.m_directory / "blocks" / "blk00000.dat").string());
+ BOOST_CHECK(chainman->ImportBlocks(import_files));
}
void chainman_mainnet_validation_test(TestDirectory& test_directory)
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.