Skip to content

Commit 5eec7fa

Browse files
committed
kernel: Add block hash type and block tree utility functions to C header
Introduce btck_BlockHash as a type-safe identifier for a block. Adds functions to retrieve block tree entries by hash or height, get block hashes and heights from entries. access the genesis block, and check if blocks are in the active chain.
1 parent f5d5d12 commit 5eec7fa

File tree

4 files changed

+364
-1
lines changed

4 files changed

+364
-1
lines changed

src/kernel/bitcoinkernel.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,7 @@ struct btck_Chain : Handle<btck_Chain, CChain> {};
490490
struct btck_BlockSpentOutputs : Handle<btck_BlockSpentOutputs, std::shared_ptr<CBlockUndo>> {};
491491
struct btck_TransactionSpentOutputs : Handle<btck_TransactionSpentOutputs, CTxUndo> {};
492492
struct btck_Coin : Handle<btck_Coin, Coin> {};
493+
struct btck_BlockHash : Handle<btck_BlockHash, uint256> {};
493494

494495
btck_Transaction* btck_transaction_create(const void* raw_transaction, size_t raw_transaction_len)
495496
{
@@ -918,6 +919,17 @@ btck_ChainstateManager* btck_chainstate_manager_create(
918919
return btck_ChainstateManager::create(std::move(chainman), opts.m_context);
919920
}
920921

922+
const btck_BlockTreeEntry* btck_chainstate_manager_get_block_tree_entry_by_hash(const btck_ChainstateManager* chainman, const btck_BlockHash* block_hash)
923+
{
924+
auto block_index = WITH_LOCK(btck_ChainstateManager::get(chainman).m_chainman->GetMutex(),
925+
return btck_ChainstateManager::get(chainman).m_chainman->m_blockman.LookupBlockIndex(btck_BlockHash::get(block_hash)));
926+
if (!block_index) {
927+
LogDebug(BCLog::KERNEL, "A block with the given hash is not indexed.");
928+
return nullptr;
929+
}
930+
return btck_BlockTreeEntry::ref(block_index);
931+
}
932+
921933
void btck_chainstate_manager_destroy(btck_ChainstateManager* chainman)
922934
{
923935
{
@@ -994,6 +1006,11 @@ int btck_block_to_bytes(const btck_Block* block, btck_WriteBytes writer, void* u
9941006
}
9951007
}
9961008

1009+
btck_BlockHash* btck_block_get_hash(const btck_Block* block)
1010+
{
1011+
return btck_BlockHash::create(btck_Block::get(block)->GetHash());
1012+
}
1013+
9971014
void btck_block_destroy(btck_Block* block)
9981015
{
9991016
delete block;
@@ -1009,6 +1026,41 @@ btck_Block* btck_block_read(const btck_ChainstateManager* chainman, const btck_B
10091026
return btck_Block::create(block);
10101027
}
10111028

1029+
int32_t btck_block_tree_entry_get_height(const btck_BlockTreeEntry* entry)
1030+
{
1031+
return btck_BlockTreeEntry::get(entry).nHeight;
1032+
}
1033+
1034+
const btck_BlockHash* btck_block_tree_entry_get_block_hash(const btck_BlockTreeEntry* entry)
1035+
{
1036+
return btck_BlockHash::ref(btck_BlockTreeEntry::get(entry).phashBlock);
1037+
}
1038+
1039+
btck_BlockHash* btck_block_hash_create(const unsigned char block_hash[32])
1040+
{
1041+
return btck_BlockHash::create(std::span<const unsigned char>{block_hash, 32});
1042+
}
1043+
1044+
btck_BlockHash* btck_block_hash_copy(const btck_BlockHash* block_hash)
1045+
{
1046+
return btck_BlockHash::copy(block_hash);
1047+
}
1048+
1049+
void btck_block_hash_to_bytes(const btck_BlockHash* block_hash, unsigned char output[32])
1050+
{
1051+
std::memcpy(output, btck_BlockHash::get(block_hash).begin(), 32);
1052+
}
1053+
1054+
int btck_block_hash_equals(const btck_BlockHash* hash1, const btck_BlockHash* hash2)
1055+
{
1056+
return btck_BlockHash::get(hash1) == btck_BlockHash::get(hash2);
1057+
}
1058+
1059+
void btck_block_hash_destroy(btck_BlockHash* hash)
1060+
{
1061+
delete hash;
1062+
}
1063+
10121064
btck_BlockSpentOutputs* btck_block_spent_outputs_read(const btck_ChainstateManager* chainman, const btck_BlockTreeEntry* entry)
10131065
{
10141066
auto block_undo{std::make_shared<CBlockUndo>()};
@@ -1121,3 +1173,21 @@ int btck_chain_get_height(const btck_Chain* chain)
11211173
LOCK(::cs_main);
11221174
return btck_Chain::get(chain).Height();
11231175
}
1176+
1177+
const btck_BlockTreeEntry* btck_chain_get_genesis(const btck_Chain* chain)
1178+
{
1179+
LOCK(::cs_main);
1180+
return btck_BlockTreeEntry::ref(btck_Chain::get(chain).Genesis());
1181+
}
1182+
1183+
const btck_BlockTreeEntry* btck_chain_get_by_height(const btck_Chain* chain, int height)
1184+
{
1185+
LOCK(::cs_main);
1186+
return btck_BlockTreeEntry::ref(btck_Chain::get(chain)[height]);
1187+
}
1188+
1189+
int btck_chain_contains(const btck_Chain* chain, const btck_BlockTreeEntry* entry)
1190+
{
1191+
LOCK(::cs_main);
1192+
return btck_Chain::get(chain).Contains(&btck_BlockTreeEntry::get(entry)) ? 1 : 0;
1193+
}

src/kernel/bitcoinkernel.h

Lines changed: 127 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,13 @@ typedef struct btck_TransactionSpentOutputs btck_TransactionSpentOutputs;
242242
*/
243243
typedef struct btck_Coin btck_Coin;
244244

245+
/**
246+
* Opaque data structure for holding a block hash.
247+
*
248+
* This is a type-safe identifier for a block.
249+
*/
250+
typedef struct btck_BlockHash btck_BlockHash;
251+
245252
/** Current sync state passed to tip changed callbacks. */
246253
typedef uint8_t btck_SynchronizationState;
247254
#define btck_SynchronizationState_INIT_REINDEX ((btck_SynchronizationState)(0))
@@ -842,7 +849,7 @@ BITCOINKERNEL_API void btck_context_destroy(btck_Context* context);
842849
///@{
843850

844851
/**
845-
* @brief Returns the previous block tree entry in the chain, or null if the current
852+
* @brief Returns the previous block tree entry in the tree, or null if the current
846853
* block tree entry is the genesis block.
847854
*
848855
* @param[in] block_tree_entry Non-null.
@@ -851,6 +858,24 @@ BITCOINKERNEL_API void btck_context_destroy(btck_Context* context);
851858
BITCOINKERNEL_API const btck_BlockTreeEntry* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_tree_entry_get_previous(
852859
const btck_BlockTreeEntry* block_tree_entry) BITCOINKERNEL_ARG_NONNULL(1);
853860

861+
/**
862+
* @brief Return the height of a certain block tree entry.
863+
*
864+
* @param[in] block_tree_entry Non-null.
865+
* @return The block height.
866+
*/
867+
BITCOINKERNEL_API int32_t BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_tree_entry_get_height(
868+
const btck_BlockTreeEntry* block_tree_entry) BITCOINKERNEL_ARG_NONNULL(1);
869+
870+
/**
871+
* @brief Return the block hash associated with a block tree entry.
872+
*
873+
* @param[in] block_tree_entry Non-null.
874+
* @return The block hash.
875+
*/
876+
BITCOINKERNEL_API const btck_BlockHash* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_tree_entry_get_block_hash(
877+
const btck_BlockTreeEntry* block_tree_entry) BITCOINKERNEL_ARG_NONNULL(1);
878+
854879
///@}
855880

856881
/** @name ChainstateManagerOptions
@@ -1001,6 +1026,18 @@ BITCOINKERNEL_API int BITCOINKERNEL_WARN_UNUSED_RESULT btck_chainstate_manager_p
10011026
BITCOINKERNEL_API const btck_Chain* BITCOINKERNEL_WARN_UNUSED_RESULT btck_chainstate_manager_get_active_chain(
10021027
const btck_ChainstateManager* chainstate_manager) BITCOINKERNEL_ARG_NONNULL(1);
10031028

1029+
/**
1030+
* @brief Retrieve a block tree entry by its block hash.
1031+
*
1032+
* @param[in] chainstate_manager Non-null.
1033+
* @param[in] block_hash Non-null.
1034+
* @return The block tree entry of the block with the passed in hash, or null if
1035+
* the block hash is not found.
1036+
*/
1037+
BITCOINKERNEL_API const btck_BlockTreeEntry* BITCOINKERNEL_WARN_UNUSED_RESULT btck_chainstate_manager_get_block_tree_entry_by_hash(
1038+
const btck_ChainstateManager* chainstate_manager,
1039+
const btck_BlockHash* block_hash) BITCOINKERNEL_ARG_NONNULL(1, 2);
1040+
10041041
/**
10051042
* Destroy the chainstate manager.
10061043
*/
@@ -1065,6 +1102,15 @@ BITCOINKERNEL_API size_t BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_count_trans
10651102
BITCOINKERNEL_API const btck_Transaction* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_get_transaction_at(
10661103
const btck_Block* block, size_t transaction_index) BITCOINKERNEL_ARG_NONNULL(1);
10671104

1105+
/**
1106+
* @brief Calculate and return the hash of a block.
1107+
*
1108+
* @param[in] block Non-null.
1109+
* @return The block hash.
1110+
*/
1111+
BITCOINKERNEL_API btck_BlockHash* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_get_hash(
1112+
const btck_Block* block) BITCOINKERNEL_ARG_NONNULL(1);
1113+
10681114
/**
10691115
* @brief Serializes the block through the passed in callback to bytes.
10701116
* This is consensus serialization that is also used for the P2P network.
@@ -1130,6 +1176,40 @@ BITCOINKERNEL_API const btck_BlockTreeEntry* BITCOINKERNEL_WARN_UNUSED_RESULT bt
11301176
BITCOINKERNEL_API int32_t BITCOINKERNEL_WARN_UNUSED_RESULT btck_chain_get_height(
11311177
const btck_Chain* chain) BITCOINKERNEL_ARG_NONNULL(1);
11321178

1179+
/**
1180+
* @brief Get the block tree entry of the genesis block.
1181+
*
1182+
* @param[in] chain Non-null.
1183+
* @return The block tree entry of the genesis block, or null if the chain is empty.
1184+
*/
1185+
BITCOINKERNEL_API const btck_BlockTreeEntry* BITCOINKERNEL_WARN_UNUSED_RESULT btck_chain_get_genesis(
1186+
const btck_Chain* chain) BITCOINKERNEL_ARG_NONNULL(1);
1187+
1188+
/**
1189+
* @brief Retrieve a block tree entry by its height in the currently active chain.
1190+
* Once retrieved there is no guarantee that it remains in the active chain.
1191+
*
1192+
* @param[in] chain Non-null.
1193+
* @param[in] block_height Height in the chain of the to be retrieved block tree entry.
1194+
* @return The block tree entry at a certain height in the currently active chain, or null
1195+
* if the height is out of bounds.
1196+
*/
1197+
BITCOINKERNEL_API const btck_BlockTreeEntry* BITCOINKERNEL_WARN_UNUSED_RESULT btck_chain_get_by_height(
1198+
const btck_Chain* chain,
1199+
int block_height) BITCOINKERNEL_ARG_NONNULL(1);
1200+
1201+
/**
1202+
* @brief Return true if the passed in chain contains the block tree entry.
1203+
*
1204+
* @param[in] chain Non-null.
1205+
* @param[in] block_tree_entry Non-null.
1206+
* @return 1 if the block_tree_entry is in the chain, 0 otherwise.
1207+
*
1208+
*/
1209+
BITCOINKERNEL_API int BITCOINKERNEL_WARN_UNUSED_RESULT btck_chain_contains(
1210+
const btck_Chain* chain,
1211+
const btck_BlockTreeEntry* block_tree_entry) BITCOINKERNEL_ARG_NONNULL(1, 2);
1212+
11331213
///@}
11341214

11351215
/** @name BlockSpentOutputs
@@ -1282,6 +1362,52 @@ BITCOINKERNEL_API void btck_coin_destroy(btck_Coin* coin);
12821362

12831363
///@}
12841364

1365+
/** @name BlockHash
1366+
* Functions for working with block hashes.
1367+
*/
1368+
///@{
1369+
1370+
/**
1371+
* @brief Create a block hash from its raw data.
1372+
*/
1373+
BITCOINKERNEL_API btck_BlockHash* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_hash_create(
1374+
const unsigned char block_hash[32]) BITCOINKERNEL_ARG_NONNULL(1);
1375+
1376+
/**
1377+
* @brief Check if two block hashes are equal.
1378+
*
1379+
* @param[in] hash1 Non-null.
1380+
* @param[in] hash2 Non-null.
1381+
* @return 0 if the block hashes are not equal.
1382+
*/
1383+
BITCOINKERNEL_API int BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_hash_equals(
1384+
const btck_BlockHash* hash1, const btck_BlockHash* hash2) BITCOINKERNEL_ARG_NONNULL(1, 2);
1385+
1386+
/**
1387+
* @brief Copy a block hash.
1388+
*
1389+
* @param[in] block_hash Non-null.
1390+
* @return The copied block hash.
1391+
*/
1392+
BITCOINKERNEL_API btck_BlockHash* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_hash_copy(
1393+
const btck_BlockHash* block_hash) BITCOINKERNEL_ARG_NONNULL(1);
1394+
1395+
/**
1396+
* @brief Serializes the block hash to bytes.
1397+
*
1398+
* @param[in] block_hash Non-null.
1399+
* @param[in] output The serialized block hash.
1400+
*/
1401+
BITCOINKERNEL_API void btck_block_hash_to_bytes(
1402+
const btck_BlockHash* block_hash, unsigned char output[32]) BITCOINKERNEL_ARG_NONNULL(1, 2);
1403+
1404+
/**
1405+
* Destroy the block hash.
1406+
*/
1407+
BITCOINKERNEL_API void btck_block_hash_destroy(btck_BlockHash* block_hash);
1408+
1409+
///@}
1410+
12851411
#ifdef __cplusplus
12861412
} // extern "C"
12871413
#endif // __cplusplus

0 commit comments

Comments
 (0)