From 096924d39d644acc826cbffd39bb34038ecee6cd Mon Sep 17 00:00:00 2001 From: stickies-v Date: Tue, 11 Nov 2025 15:09:56 +0000 Subject: [PATCH] kernel: add btck_block_tree_entry_equals BlockTreeEntry objects are often compared. By exposing an equality function, clients don't have to implement more expensive comparisons based on height and block hash. --- src/kernel/bitcoinkernel.cpp | 5 ++++ src/kernel/bitcoinkernel.h | 11 ++++++++ src/kernel/bitcoinkernel_wrapper.h | 5 ++++ src/test/kernel/test_kernel.cpp | 42 ++++++++++++++++++++++++++++++ 4 files changed, 63 insertions(+) diff --git a/src/kernel/bitcoinkernel.cpp b/src/kernel/bitcoinkernel.cpp index 240255bbd52..f59744bc519 100644 --- a/src/kernel/bitcoinkernel.cpp +++ b/src/kernel/bitcoinkernel.cpp @@ -1104,6 +1104,11 @@ const btck_BlockHash* btck_block_tree_entry_get_block_hash(const btck_BlockTreeE return btck_BlockHash::ref(btck_BlockTreeEntry::get(entry).phashBlock); } +int btck_block_tree_entry_equals(const btck_BlockTreeEntry* entry1, const btck_BlockTreeEntry* entry2) +{ + return &btck_BlockTreeEntry::get(entry1) == &btck_BlockTreeEntry::get(entry2); +} + btck_BlockHash* btck_block_hash_create(const unsigned char block_hash[32]) { return btck_BlockHash::create(std::span{block_hash, 32}); diff --git a/src/kernel/bitcoinkernel.h b/src/kernel/bitcoinkernel.h index 4c94b59ff77..7ff9dcc05a9 100644 --- a/src/kernel/bitcoinkernel.h +++ b/src/kernel/bitcoinkernel.h @@ -922,6 +922,17 @@ BITCOINKERNEL_API int32_t BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_tree_entry BITCOINKERNEL_API const btck_BlockHash* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_tree_entry_get_block_hash( const btck_BlockTreeEntry* block_tree_entry) BITCOINKERNEL_ARG_NONNULL(1); +/** + * @brief Check if two block tree entries are equal. Two block tree entries are equal when they + * point to the same block. + * + * @param[in] entry1 Non-null. + * @param[in] entry2 Non-null. + * @return 1 if the block tree entries are equal, 0 otherwise. + */ +BITCOINKERNEL_API int BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_tree_entry_equals( + const btck_BlockTreeEntry* entry1, const btck_BlockTreeEntry* entry2) BITCOINKERNEL_ARG_NONNULL(1, 2); + ///@} /** @name ChainstateManagerOptions diff --git a/src/kernel/bitcoinkernel_wrapper.h b/src/kernel/bitcoinkernel_wrapper.h index b847dde5002..764c8a3d2f4 100644 --- a/src/kernel/bitcoinkernel_wrapper.h +++ b/src/kernel/bitcoinkernel_wrapper.h @@ -786,6 +786,11 @@ public: { } + bool operator==(const BlockTreeEntry& other) const + { + return btck_block_tree_entry_equals(get(), other.get()) != 0; + } + std::optional GetPrevious() const { auto entry{btck_block_tree_entry_get_previous(get())}; diff --git a/src/test/kernel/test_kernel.cpp b/src/test/kernel/test_kernel.cpp index e1c9376d50a..e98a9c50998 100644 --- a/src/test/kernel/test_kernel.cpp +++ b/src/test/kernel/test_kernel.cpp @@ -797,6 +797,48 @@ BOOST_AUTO_TEST_CASE(btck_block_hash_tests) CheckHandle(block_hash, block_hash_2); } +BOOST_AUTO_TEST_CASE(btck_block_tree_entry_tests) +{ + auto test_directory{TestDirectory{"block_tree_entry_test_bitcoin_kernel"}}; + auto notifications{std::make_shared()}; + auto context{create_context(notifications, ChainType::REGTEST)}; + auto chainman{create_chainman( + test_directory, + /*reindex=*/false, + /*wipe_chainstate=*/false, + /*block_tree_db_in_memory=*/true, + /*chainstate_db_in_memory=*/true, + context)}; + + // Process a couple of blocks + for (size_t i{0}; i < 3; i++) { + Block block{hex_string_to_byte_vec(REGTEST_BLOCK_DATA[i])}; + bool new_block{false}; + chainman->ProcessBlock(block, &new_block); + BOOST_CHECK(new_block); + } + + auto chain{chainman->GetChain()}; + auto entry_0{chain.GetByHeight(0)}; + auto entry_1{chain.GetByHeight(1)}; + auto entry_2{chain.GetByHeight(2)}; + + // Test inequality + BOOST_CHECK(entry_0 != entry_1); + BOOST_CHECK(entry_1 != entry_2); + BOOST_CHECK(entry_0 != entry_2); + + // Test equality with same entry + BOOST_CHECK(entry_0 == chain.GetByHeight(0)); + BOOST_CHECK(entry_0 == BlockTreeEntry{entry_0}); + BOOST_CHECK(entry_1 == entry_1); + + // Test GetPrevious + auto prev{entry_1.GetPrevious()}; + BOOST_CHECK(prev.has_value()); + BOOST_CHECK(prev.value() == entry_0); +} + BOOST_AUTO_TEST_CASE(btck_chainman_in_memory_tests) { auto in_memory_test_directory{TestDirectory{"in-memory_test_bitcoin_kernel"}};