kernel: Add Handle/View pattern for BlockValidationState
What changed, and why it matters
This commit is a routine internal API refactor for Bitcoin Core's experimental libbitcoinkernel C API. It adds create/copy/destroy functions for a block-validation state object and splits a C++ wrapper class into a read-only 'View' and an owning 'Handle'. There is no security fix, no bug fix, and no externally reported issue. It simply lets outside code allocate and own these state objects.
No security action required. Treat as normal code-review/merge for API design and memory-ownership correctness.
Security signals we found
No security-relevant keywords in commit title or message
No bug-fix description or CVE reference present
Change is additive API surface (create/copy/destroy) and type refactor
No evidence of memory corruption, consensus, or DoS fix in diff
Evidence from the diff
The change introduces lifecycle C functions for btck_BlockValidationState (create/copy/destroy) and a BlockValidationStateApi<> template shared by BlockValidationStateView (non-owning) and BlockValidationState (owning Handle). Validation callbacks now pass a BlockValidationStateView instead of a const BlockValidationState, clarifying that the callback does not own the object. This is a pure API ergonomics/lifecycle refactor; no validation logic, memory-safety bug, or vulnerability is addressed.
Changed components
src/kernel/bitcoinkernel.cppsrc/kernel/bitcoinkernel.hsrc/kernel/bitcoinkernel_wrapper.hsrc/bitcoin-chainstate.cppsrc/test/kernel/test_kernel.cppInspect captured patch +67 / −18
diff --git a/src/bitcoin-chainstate.cpp b/src/bitcoin-chainstate.cpp
index 71d0f3e9..ae215c19 100644
--- a/src/bitcoin-chainstate.cpp
+++ b/src/bitcoin-chainstate.cpp
@@ -57,7 +57,7 @@ public:
std::optional<std::string> m_expected_valid_block = std::nullopt;
- void BlockChecked(const Block block, const BlockValidationState state) override
+ void BlockChecked(Block block, BlockValidationStateView state) override
{
auto mode{state.GetValidationMode()};
switch (mode) {
diff --git a/src/kernel/bitcoinkernel.cpp b/src/kernel/bitcoinkernel.cpp
index 8c7abef5..497527ed 100644
--- a/src/kernel/bitcoinkernel.cpp
+++ b/src/kernel/bitcoinkernel.cpp
@@ -885,6 +885,21 @@ const btck_BlockTreeEntry* btck_block_tree_entry_get_previous(const btck_BlockTr
return btck_BlockTreeEntry::ref(btck_BlockTreeEntry::get(entry).pprev);
}
+btck_BlockValidationState* btck_block_validation_state_create()
+{
+ return btck_BlockValidationState::create();
+}
+
+btck_BlockValidationState* btck_block_validation_state_copy(const btck_BlockValidationState* state)
+{
+ return btck_BlockValidationState::copy(state);
+}
+
+void btck_block_validation_state_destroy(btck_BlockValidationState* state)
+{
+ delete state;
+}
+
btck_ValidationMode btck_block_validation_state_get_validation_mode(const btck_BlockValidationState* block_validation_state_)
{
auto& block_validation_state = btck_BlockValidationState::get(block_validation_state_);
diff --git a/src/kernel/bitcoinkernel.h b/src/kernel/bitcoinkernel.h
index 53a760cd..94d90cea 100644
--- a/src/kernel/bitcoinkernel.h
+++ b/src/kernel/bitcoinkernel.h
@@ -1251,17 +1251,37 @@ BITCOINKERNEL_API void btck_block_destroy(btck_Block* block);
///@{
/**
- * Returns the validation mode from an opaque block validation state pointer.
+ * Create a new btck_BlockValidationState.
+ */
+BITCOINKERNEL_API btck_BlockValidationState* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_validation_state_create();
+
+/**
+ * Returns the validation mode from an opaque btck_BlockValidationState pointer.
*/
BITCOINKERNEL_API btck_ValidationMode btck_block_validation_state_get_validation_mode(
const btck_BlockValidationState* block_validation_state) BITCOINKERNEL_ARG_NONNULL(1);
/**
- * Returns the validation result from an opaque block validation state pointer.
+ * Returns the validation result from an opaque btck_BlockValidationState pointer.
*/
BITCOINKERNEL_API btck_BlockValidationResult btck_block_validation_state_get_block_validation_result(
const btck_BlockValidationState* block_validation_state) BITCOINKERNEL_ARG_NONNULL(1);
+/**
+ * @brief Copies the btck_BlockValidationState.
+ *
+ * @param[in] block_validation_state Non-null.
+ * @return The copied btck_BlockValidationState.
+ */
+BITCOINKERNEL_API btck_BlockValidationState* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_validation_state_copy(
+ const btck_BlockValidationState* block_validation_state) BITCOINKERNEL_ARG_NONNULL(1);
+
+/**
+ * Destroy the btck_BlockValidationState.
+ */
+BITCOINKERNEL_API void btck_block_validation_state_destroy(
+ btck_BlockValidationState* block_validation_state) BITCOINKERNEL_ARG_NONNULL(1);
+
///@}
/** @name Chain
diff --git a/src/kernel/bitcoinkernel_wrapper.h b/src/kernel/bitcoinkernel_wrapper.h
index 5c1b8d07..14f29d03 100644
--- a/src/kernel/bitcoinkernel_wrapper.h
+++ b/src/kernel/bitcoinkernel_wrapper.h
@@ -685,7 +685,7 @@ public:
}
};
-class BlockHashView: public View<btck_BlockHash>, public BlockHashApi<BlockHashView>
+class BlockHashView : public View<btck_BlockHash>, public BlockHashApi<BlockHashView>
{
public:
explicit BlockHashView(const btck_BlockHash* ptr) : View{ptr} {}
@@ -831,36 +831,50 @@ public:
virtual void FatalErrorHandler(std::string_view error) {}
};
-class BlockValidationState
+template <typename Derived>
+class BlockValidationStateApi
{
private:
- const btck_BlockValidationState* m_state;
-
-public:
- BlockValidationState(const btck_BlockValidationState* state) : m_state{state} {}
+ auto impl() const
+ {
+ return static_cast<const Derived*>(this)->get();
+ }
- BlockValidationState(const BlockValidationState&) = delete;
- BlockValidationState& operator=(const BlockValidationState&) = delete;
- BlockValidationState(BlockValidationState&&) = delete;
- BlockValidationState& operator=(BlockValidationState&&) = delete;
+ friend Derived;
+ BlockValidationStateApi() = default;
+public:
ValidationMode GetValidationMode() const
{
- return static_cast<ValidationMode>(btck_block_validation_state_get_validation_mode(m_state));
+ return static_cast<ValidationMode>(btck_block_validation_state_get_validation_mode(impl()));
}
BlockValidationResult GetBlockValidationResult() const
{
- return static_cast<BlockValidationResult>(btck_block_validation_state_get_block_validation_result(m_state));
+ return static_cast<BlockValidationResult>(btck_block_validation_state_get_block_validation_result(impl()));
}
};
+class BlockValidationStateView : public View<btck_BlockValidationState>, public BlockValidationStateApi<BlockValidationStateView>
+{
+public:
+ explicit BlockValidationStateView(const btck_BlockValidationState* ptr) : View{ptr} {}
+};
+
+class BlockValidationState : public Handle<btck_BlockValidationState, btck_block_validation_state_copy, btck_block_validation_state_destroy>, public BlockValidationStateApi<BlockValidationState>
+{
+public:
+ explicit BlockValidationState() : Handle{btck_block_validation_state_create()} {}
+
+ BlockValidationState(const BlockValidationStateView& view) : Handle{view} {}
+};
+
class ValidationInterface
{
public:
virtual ~ValidationInterface() = default;
- virtual void BlockChecked(Block block, const BlockValidationState state) {}
+ virtual void BlockChecked(Block block, BlockValidationStateView state) {}
virtual void PowValidBlock(BlockTreeEntry entry, Block block) {}
@@ -918,7 +932,7 @@ public:
btck_ValidationInterfaceCallbacks{
.user_data = heap_vi.release(),
.user_data_destroy = +[](void* user_data) { delete static_cast<user_type>(user_data); },
- .block_checked = +[](void* user_data, btck_Block* block, const btck_BlockValidationState* state) { (*static_cast<user_type>(user_data))->BlockChecked(Block{block}, BlockValidationState{state}); },
+ .block_checked = +[](void* user_data, btck_Block* block, const btck_BlockValidationState* state) { (*static_cast<user_type>(user_data))->BlockChecked(Block{block}, BlockValidationStateView{state}); },
.pow_valid_block = +[](void* user_data, btck_Block* block, const btck_BlockTreeEntry* entry) { (*static_cast<user_type>(user_data))->PowValidBlock(BlockTreeEntry{entry}, Block{block}); },
.block_connected = +[](void* user_data, btck_Block* block, const btck_BlockTreeEntry* entry) { (*static_cast<user_type>(user_data))->BlockConnected(Block{block}, BlockTreeEntry{entry}); },
.block_disconnected = +[](void* user_data, btck_Block* block, const btck_BlockTreeEntry* entry) { (*static_cast<user_type>(user_data))->BlockDisconnected(Block{block}, BlockTreeEntry{entry}); },
diff --git a/src/test/kernel/test_kernel.cpp b/src/test/kernel/test_kernel.cpp
index 07f1d3cf..8d6a2287 100644
--- a/src/test/kernel/test_kernel.cpp
+++ b/src/test/kernel/test_kernel.cpp
@@ -145,7 +145,7 @@ class TestValidationInterface : public ValidationInterface
public:
std::optional<std::vector<std::byte>> m_expected_valid_block = std::nullopt;
- void BlockChecked(Block block, const BlockValidationState state) override
+ void BlockChecked(Block block, BlockValidationStateView state) override
{
if (m_expected_valid_block.has_value()) {
auto ser_block{block.ToBytes()};
Why this scored 15/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.