Skip to content

Commit 4a261e9

Browse files
yuviccsedited
andcommitted
kernel: Add support for block headers
Introduces btck_BlockHeader type with accessor methods and btck_chainstate_manager_process_block_header() for validating headers without full blocks. Also, adds btck_chainstate_manager_get_best_entry() to query the header with most cumulative proof-of-work. Co-authored-by: TheCharlatan <[email protected]>
1 parent 27a3e3d commit 4a261e9

File tree

4 files changed

+369
-0
lines changed

4 files changed

+369
-0
lines changed

src/kernel/bitcoinkernel.cpp

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,7 @@ struct btck_TransactionInput : Handle<btck_TransactionInput, CTxIn> {};
496496
struct btck_TransactionOutPoint: Handle<btck_TransactionOutPoint, COutPoint> {};
497497
struct btck_Txid: Handle<btck_Txid, Txid> {};
498498
struct btck_PrecomputedTransactionData : Handle<btck_PrecomputedTransactionData, PrecomputedTransactionData> {};
499+
struct btck_BlockHeader: Handle<btck_BlockHeader, CBlockHeader> {};
499500

500501
btck_Transaction* btck_transaction_create(const void* raw_transaction, size_t raw_transaction_len)
501502
{
@@ -1044,6 +1045,12 @@ const btck_BlockTreeEntry* btck_chainstate_manager_get_block_tree_entry_by_hash(
10441045
return btck_BlockTreeEntry::ref(block_index);
10451046
}
10461047

1048+
const btck_BlockTreeEntry* btck_chainstate_manager_get_best_entry(const btck_ChainstateManager* chainstate_manager)
1049+
{
1050+
auto& chainman = *btck_ChainstateManager::get(chainstate_manager).m_chainman;
1051+
return btck_BlockTreeEntry::ref(WITH_LOCK(chainman.GetMutex(), return chainman.m_best_header));
1052+
}
1053+
10471054
void btck_chainstate_manager_destroy(btck_ChainstateManager* chainman)
10481055
{
10491056
{
@@ -1112,6 +1119,12 @@ const btck_Transaction* btck_block_get_transaction_at(const btck_Block* block, s
11121119
return btck_Transaction::ref(&btck_Block::get(block)->vtx[index]);
11131120
}
11141121

1122+
btck_BlockHeader* btck_block_get_header(const btck_Block* block)
1123+
{
1124+
const auto& block_ptr = btck_Block::get(block);
1125+
return btck_BlockHeader::create(block_ptr->GetBlockHeader());
1126+
}
1127+
11151128
int btck_block_to_bytes(const btck_Block* block, btck_WriteBytes writer, void* user_data)
11161129
{
11171130
try {
@@ -1143,6 +1156,11 @@ btck_Block* btck_block_read(const btck_ChainstateManager* chainman, const btck_B
11431156
return btck_Block::create(block);
11441157
}
11451158

1159+
btck_BlockHeader* btck_block_tree_entry_get_block_header(const btck_BlockTreeEntry* entry)
1160+
{
1161+
return btck_BlockHeader::create(btck_BlockTreeEntry::get(entry).GetBlockHeader());
1162+
}
1163+
11461164
int32_t btck_block_tree_entry_get_height(const btck_BlockTreeEntry* entry)
11471165
{
11481166
return btck_BlockTreeEntry::get(entry).nHeight;
@@ -1279,6 +1297,22 @@ int btck_chainstate_manager_process_block(
12791297
return result ? 0 : -1;
12801298
}
12811299

1300+
int btck_chainstate_manager_process_block_header(
1301+
btck_ChainstateManager* chainstate_manager,
1302+
const btck_BlockHeader* header,
1303+
btck_BlockValidationState* state)
1304+
{
1305+
try {
1306+
auto& chainman = btck_ChainstateManager::get(chainstate_manager).m_chainman;
1307+
auto result = chainman->ProcessNewBlockHeaders({&btck_BlockHeader::get(header), 1}, /*min_pow_checked=*/true, btck_BlockValidationState::get(state), /*ppindex=*/nullptr);
1308+
1309+
return result ? 0 : -1;
1310+
} catch (std::exception& e) {
1311+
LogError("Failed to process block header: %s", e.what());
1312+
return -1;
1313+
}
1314+
}
1315+
12821316
const btck_Chain* btck_chainstate_manager_get_active_chain(const btck_ChainstateManager* chainman)
12831317
{
12841318
return btck_Chain::ref(&WITH_LOCK(btck_ChainstateManager::get(chainman).m_chainman->GetMutex(), return btck_ChainstateManager::get(chainman).m_chainman->ActiveChain()));
@@ -1301,3 +1335,61 @@ int btck_chain_contains(const btck_Chain* chain, const btck_BlockTreeEntry* entr
13011335
LOCK(::cs_main);
13021336
return btck_Chain::get(chain).Contains(&btck_BlockTreeEntry::get(entry)) ? 1 : 0;
13031337
}
1338+
1339+
btck_BlockHeader* btck_block_header_create(const void* raw_block_header, size_t raw_block_header_len)
1340+
{
1341+
if (raw_block_header == nullptr && raw_block_header_len != 0) {
1342+
return nullptr;
1343+
}
1344+
auto header{std::make_unique<CBlockHeader>()};
1345+
DataStream stream{std::span{reinterpret_cast<const std::byte*>(raw_block_header), raw_block_header_len}};
1346+
1347+
try {
1348+
stream >> *header;
1349+
} catch (...) {
1350+
LogError("Block header decode failed.");
1351+
return nullptr;
1352+
}
1353+
1354+
return btck_BlockHeader::ref(header.release());
1355+
}
1356+
1357+
btck_BlockHeader* btck_block_header_copy(const btck_BlockHeader* header)
1358+
{
1359+
return btck_BlockHeader::copy(header);
1360+
}
1361+
1362+
btck_BlockHash* btck_block_header_get_hash(const btck_BlockHeader* header)
1363+
{
1364+
return btck_BlockHash::create(btck_BlockHeader::get(header).GetHash());
1365+
}
1366+
1367+
const btck_BlockHash* btck_block_header_get_prev_hash(const btck_BlockHeader* header)
1368+
{
1369+
return btck_BlockHash::ref(&btck_BlockHeader::get(header).hashPrevBlock);
1370+
}
1371+
1372+
uint32_t btck_block_header_get_timestamp(const btck_BlockHeader* header)
1373+
{
1374+
return btck_BlockHeader::get(header).nTime;
1375+
}
1376+
1377+
uint32_t btck_block_header_get_bits(const btck_BlockHeader* header)
1378+
{
1379+
return btck_BlockHeader::get(header).nBits;
1380+
}
1381+
1382+
int32_t btck_block_header_get_version(const btck_BlockHeader* header)
1383+
{
1384+
return btck_BlockHeader::get(header).nVersion;
1385+
}
1386+
1387+
uint32_t btck_block_header_get_nonce(const btck_BlockHeader* header)
1388+
{
1389+
return btck_BlockHeader::get(header).nNonce;
1390+
}
1391+
1392+
void btck_block_header_destroy(btck_BlockHeader* header)
1393+
{
1394+
delete header;
1395+
}

src/kernel/bitcoinkernel.h

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,8 +292,18 @@ typedef struct btck_TransactionOutPoint btck_TransactionOutPoint;
292292
*/
293293
typedef struct btck_PrecomputedTransactionData btck_PrecomputedTransactionData;
294294

295+
/**
296+
* Opaque data structure for holding a btck_Txid.
297+
*
298+
* This is a type-safe identifier for a transaction.
299+
*/
295300
typedef struct btck_Txid btck_Txid;
296301

302+
/**
303+
* Opaque data structure for holding a btck_BlockHeader.
304+
*/
305+
typedef struct btck_BlockHeader btck_BlockHeader;
306+
297307
/** Current sync state passed to tip changed callbacks. */
298308
typedef uint8_t btck_SynchronizationState;
299309
#define btck_SynchronizationState_INIT_REINDEX ((btck_SynchronizationState)(0))
@@ -958,6 +968,15 @@ BITCOINKERNEL_API void btck_context_destroy(btck_Context* context);
958968
BITCOINKERNEL_API const btck_BlockTreeEntry* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_tree_entry_get_previous(
959969
const btck_BlockTreeEntry* block_tree_entry) BITCOINKERNEL_ARG_NONNULL(1);
960970

971+
/**
972+
* @brief Return the btck_BlockHeader associated with this entry.
973+
*
974+
* @param[in] block_tree_entry Non-null.
975+
* @return btck_BlockHeader.
976+
*/
977+
BITCOINKERNEL_API btck_BlockHeader* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_tree_entry_get_block_header(
978+
const btck_BlockTreeEntry* block_tree_entry) BITCOINKERNEL_ARG_NONNULL(1);
979+
961980
/**
962981
* @brief Return the height of a certain block tree entry.
963982
*
@@ -1083,6 +1102,29 @@ BITCOINKERNEL_API void btck_chainstate_manager_options_destroy(btck_ChainstateMa
10831102
BITCOINKERNEL_API btck_ChainstateManager* BITCOINKERNEL_WARN_UNUSED_RESULT btck_chainstate_manager_create(
10841103
const btck_ChainstateManagerOptions* chainstate_manager_options) BITCOINKERNEL_ARG_NONNULL(1);
10851104

1105+
/**
1106+
* @brief Get the btck_BlockTreeEntry whose associated btck_BlockHeader has the most
1107+
* known cumulative proof of work.
1108+
*
1109+
* @param[in] chainstate_manager Non-null.
1110+
* @return The btck_BlockTreeEntry.
1111+
*/
1112+
BITCOINKERNEL_API const btck_BlockTreeEntry* BITCOINKERNEL_WARN_UNUSED_RESULT btck_chainstate_manager_get_best_entry(
1113+
const btck_ChainstateManager* chainstate_manager) BITCOINKERNEL_ARG_NONNULL(1);
1114+
1115+
/**
1116+
* @brief Processes and validates the provided btck_BlockHeader.
1117+
*
1118+
* @param[in] chainstate_manager Non-null.
1119+
* @param[in] header Non-null btck_BlockHeader to be validated.
1120+
* @param[out] block_validation_state The result of the btck_BlockHeader validation.
1121+
* @return 0 if btck_BlockHeader processing completed successfully, non-zero on error.
1122+
*/
1123+
BITCOINKERNEL_API int BITCOINKERNEL_WARN_UNUSED_RESULT btck_chainstate_manager_process_block_header(
1124+
btck_ChainstateManager* chainstate_manager,
1125+
const btck_BlockHeader* header,
1126+
btck_BlockValidationState* block_validation_state) BITCOINKERNEL_ARG_NONNULL(1, 2, 3);
1127+
10861128
/**
10871129
* @brief Triggers the start of a reindex if the wipe options were previously
10881130
* set for the chainstate manager. Can also import an array of existing block
@@ -1214,6 +1256,17 @@ BITCOINKERNEL_API size_t BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_count_trans
12141256
BITCOINKERNEL_API const btck_Transaction* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_get_transaction_at(
12151257
const btck_Block* block, size_t transaction_index) BITCOINKERNEL_ARG_NONNULL(1);
12161258

1259+
/**
1260+
* @brief Get the btck_BlockHeader from the block.
1261+
*
1262+
* Creates a new btck_BlockHeader object from the block's header data.
1263+
*
1264+
* @param[in] block Non-null btck_Block
1265+
* @return btck_BlockHeader.
1266+
*/
1267+
BITCOINKERNEL_API btck_BlockHeader* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_get_header(
1268+
const btck_Block* block) BITCOINKERNEL_ARG_NONNULL(1);
1269+
12171270
/**
12181271
* @brief Calculate and return the hash of a block.
12191272
*
@@ -1635,6 +1688,92 @@ BITCOINKERNEL_API void btck_block_hash_destroy(btck_BlockHash* block_hash);
16351688

16361689
///@}
16371690

1691+
/**
1692+
* @name Block Header
1693+
* Functions for working with block headers.
1694+
*/
1695+
///@{
1696+
1697+
/**
1698+
* @brief Create a btck_BlockHeader from serialized data.
1699+
*
1700+
* @param[in] raw_block_header Non-null, serialized header data (80 bytes)
1701+
* @param[in] raw_block_header_len Length of serialized header (must be 80)
1702+
* @return btck_BlockHeader, or null on error.
1703+
*/
1704+
BITCOINKERNEL_API btck_BlockHeader* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_header_create(
1705+
const void* raw_block_header, size_t raw_block_header_len);
1706+
1707+
/**
1708+
* @brief Copy a btck_BlockHeader.
1709+
*
1710+
* @param[in] header Non-null btck_BlockHeader.
1711+
* @return Copied btck_BlockHeader.
1712+
*/
1713+
BITCOINKERNEL_API btck_BlockHeader* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_header_copy(
1714+
const btck_BlockHeader* header) BITCOINKERNEL_ARG_NONNULL(1);
1715+
1716+
/**
1717+
* @brief Get the btck_BlockHash.
1718+
*
1719+
* @param[in] header Non-null header
1720+
* @return btck_BlockHash.
1721+
*/
1722+
BITCOINKERNEL_API btck_BlockHash* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_header_get_hash(
1723+
const btck_BlockHeader* header) BITCOINKERNEL_ARG_NONNULL(1);
1724+
1725+
/**
1726+
* @brief Get the previous btck_BlockHash from btck_BlockHeader. The returned hash is unowned and only valid for the lifetime of the btck_BlockHeader.
1727+
*
1728+
* @param[in] header Non-null btck_BlockHeader
1729+
* @return Previous btck_BlockHash
1730+
*/
1731+
BITCOINKERNEL_API const btck_BlockHash* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_header_get_prev_hash(
1732+
const btck_BlockHeader* header) BITCOINKERNEL_ARG_NONNULL(1);
1733+
1734+
/**
1735+
* @brief Get the timestamp from btck_BlockHeader.
1736+
*
1737+
* @param[in] header Non-null btck_BlockHeader
1738+
* @return Block timestamp (Unix epoch seconds)
1739+
*/
1740+
BITCOINKERNEL_API uint32_t BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_header_get_timestamp(
1741+
const btck_BlockHeader* header) BITCOINKERNEL_ARG_NONNULL(1);
1742+
1743+
/**
1744+
* @brief Get the nBits difficulty target from btck_BlockHeader.
1745+
*
1746+
* @param[in] header Non-null btck_BlockHeader
1747+
* @return Difficulty target (compact format)
1748+
*/
1749+
BITCOINKERNEL_API uint32_t BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_header_get_bits(
1750+
const btck_BlockHeader* header) BITCOINKERNEL_ARG_NONNULL(1);
1751+
1752+
/**
1753+
* @brief Get the version from btck_BlockHeader.
1754+
*
1755+
* @param[in] header Non-null btck_BlockHeader
1756+
* @return Block version
1757+
*/
1758+
BITCOINKERNEL_API int32_t BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_header_get_version(
1759+
const btck_BlockHeader* header) BITCOINKERNEL_ARG_NONNULL(1);
1760+
1761+
/**
1762+
* @brief Get the nonce from btck_BlockHeader.
1763+
*
1764+
* @param[in] header Non-null btck_BlockHeader
1765+
* @return Nonce
1766+
*/
1767+
BITCOINKERNEL_API uint32_t BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_header_get_nonce(
1768+
const btck_BlockHeader* header) BITCOINKERNEL_ARG_NONNULL(1);
1769+
1770+
/**
1771+
* Destroy the btck_BlockHeader.
1772+
*/
1773+
BITCOINKERNEL_API void btck_block_header_destroy(btck_BlockHeader* header);
1774+
1775+
///@}
1776+
16381777
#ifdef __cplusplus
16391778
} // extern "C"
16401779
#endif // __cplusplus

0 commit comments

Comments
 (0)