Skip to content

Commit 966cc6d

Browse files
committed
Add header handling
1 parent 3916b85 commit 966cc6d

File tree

5 files changed

+255
-30
lines changed

5 files changed

+255
-30
lines changed

src/core/block.rs

Lines changed: 145 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
use std::{ffi::c_void, marker::PhantomData};
22

33
use libbitcoinkernel_sys::{
4-
btck_Block, btck_BlockHash, btck_BlockSpentOutputs, btck_Coin, btck_TransactionSpentOutputs,
5-
btck_block_copy, btck_block_count_transactions, btck_block_create, btck_block_destroy,
6-
btck_block_get_hash, btck_block_get_transaction_at, btck_block_hash_copy,
7-
btck_block_hash_create, btck_block_hash_destroy, btck_block_hash_equals,
8-
btck_block_hash_to_bytes, btck_block_spent_outputs_copy, btck_block_spent_outputs_count,
4+
btck_Block, btck_BlockHash, btck_BlockHeader, btck_BlockSpentOutputs, btck_Coin,
5+
btck_TransactionSpentOutputs, btck_block_copy, btck_block_count_transactions,
6+
btck_block_create, btck_block_destroy, btck_block_get_hash, btck_block_get_header,
7+
btck_block_get_transaction_at, btck_block_hash_copy, btck_block_hash_create,
8+
btck_block_hash_destroy, btck_block_hash_equals, btck_block_hash_to_bytes,
9+
btck_block_header_copy, btck_block_header_create, btck_block_header_destroy,
10+
btck_block_header_get_hash, btck_block_spent_outputs_copy, btck_block_spent_outputs_count,
911
btck_block_spent_outputs_destroy, btck_block_spent_outputs_get_transaction_spent_outputs_at,
1012
btck_block_to_bytes, btck_coin_confirmation_height, btck_coin_copy, btck_coin_destroy,
1113
btck_coin_get_output, btck_coin_is_coinbase, btck_transaction_spent_outputs_copy,
@@ -72,6 +74,15 @@ impl AsPtr<btck_BlockHash> for BlockHash {
7274
}
7375
}
7476

77+
impl<'a> FromPtr<btck_BlockHash> for BlockHashRef<'a> {
78+
unsafe fn from_ptr(ptr: *const btck_BlockHash) -> Self {
79+
BlockHashRef {
80+
inner: ptr,
81+
marker: PhantomData,
82+
}
83+
}
84+
}
85+
7586
impl FromMutPtr<btck_BlockHash> for BlockHash {
7687
unsafe fn from_ptr(ptr: *mut btck_BlockHash) -> Self {
7788
BlockHash { inner: ptr }
@@ -166,15 +177,6 @@ impl<'a> AsPtr<btck_BlockHash> for BlockHashRef<'a> {
166177
}
167178
}
168179

169-
impl<'a> FromPtr<btck_BlockHash> for BlockHashRef<'a> {
170-
unsafe fn from_ptr(ptr: *const btck_BlockHash) -> Self {
171-
BlockHashRef {
172-
inner: ptr,
173-
marker: PhantomData,
174-
}
175-
}
176-
}
177-
178180
impl<'a> BlockHashExt for BlockHashRef<'a> {}
179181

180182
impl<'a> Clone for BlockHashRef<'a> {
@@ -209,6 +211,114 @@ impl<'a> Eq for BlockHashRef<'a> {}
209211

210212
impl<'a> Copy for BlockHashRef<'a> {}
211213

214+
/// Common operations for block headers, implemented by both owned and borrow types.
215+
pub trait BlockHeaderExt: AsPtr<btck_BlockHeader> {
216+
/// Return the block hash of the header.
217+
fn hash(&self) -> BlockHash {
218+
unsafe { BlockHash::from_ptr(btck_block_header_get_hash(self.as_ptr())) }
219+
}
220+
}
221+
222+
/// A Bitcoin block header.
223+
///
224+
/// Block headers can be created from raw serialized data or retrieved from the
225+
/// chain or blocks.
226+
pub struct BlockHeader {
227+
inner: *mut btck_BlockHeader,
228+
}
229+
230+
unsafe impl Send for BlockHeader {}
231+
unsafe impl Sync for BlockHeader {}
232+
233+
impl BlockHeader {
234+
pub fn new(header_bytes: &[u8]) -> Result<Self, KernelError> {
235+
let inner = unsafe {
236+
btck_block_header_create(header_bytes.as_ptr() as *const c_void, header_bytes.len())
237+
};
238+
239+
if inner.is_null() {
240+
Err(KernelError::Internal(
241+
"Failed to create header from bytes".to_string(),
242+
))
243+
} else {
244+
Ok(BlockHeader { inner })
245+
}
246+
}
247+
248+
pub fn as_ref(&self) -> BlockHeaderRef<'_> {
249+
unsafe { BlockHeaderRef::from_ptr(self.inner as *const _) }
250+
}
251+
}
252+
253+
impl FromMutPtr<btck_BlockHeader> for BlockHeader {
254+
unsafe fn from_ptr(ptr: *mut btck_BlockHeader) -> Self {
255+
BlockHeader { inner: ptr }
256+
}
257+
}
258+
259+
impl AsPtr<btck_BlockHeader> for BlockHeader {
260+
fn as_ptr(&self) -> *const btck_BlockHeader {
261+
self.inner as *const _
262+
}
263+
}
264+
265+
impl BlockHeaderExt for BlockHeader {}
266+
267+
impl Clone for BlockHeader {
268+
fn clone(&self) -> Self {
269+
BlockHeader {
270+
inner: unsafe { btck_block_header_copy(self.inner) },
271+
}
272+
}
273+
}
274+
275+
impl Drop for BlockHeader {
276+
fn drop(&mut self) {
277+
unsafe { btck_block_header_destroy(self.inner) }
278+
}
279+
}
280+
281+
pub struct BlockHeaderRef<'a> {
282+
inner: *const btck_BlockHeader,
283+
marker: PhantomData<&'a ()>,
284+
}
285+
286+
unsafe impl<'a> Send for BlockHeaderRef<'a> {}
287+
unsafe impl<'a> Sync for BlockHeaderRef<'a> {}
288+
289+
impl<'a> BlockHeaderRef<'a> {
290+
pub fn to_owned(&self) -> BlockHeader {
291+
BlockHeader {
292+
inner: unsafe { btck_block_header_copy(self.inner) },
293+
}
294+
}
295+
}
296+
297+
impl<'a> AsPtr<btck_BlockHeader> for BlockHeaderRef<'a> {
298+
fn as_ptr(&self) -> *const btck_BlockHeader {
299+
self.inner
300+
}
301+
}
302+
303+
impl<'a> FromPtr<btck_BlockHeader> for BlockHeaderRef<'a> {
304+
unsafe fn from_ptr(ptr: *const btck_BlockHeader) -> Self {
305+
BlockHeaderRef {
306+
inner: ptr,
307+
marker: PhantomData,
308+
}
309+
}
310+
}
311+
312+
impl<'a> BlockHeaderExt for BlockHeaderRef<'a> {}
313+
314+
impl<'a> Copy for BlockHeaderRef<'a> {}
315+
316+
impl<'a> Clone for BlockHeaderRef<'a> {
317+
fn clone(&self) -> Self {
318+
*self
319+
}
320+
}
321+
212322
/// A Bitcoin block containing a header and transactions.
213323
///
214324
/// Blocks can be created from raw serialized data or retrieved from the blockchain.
@@ -248,6 +358,10 @@ impl Block {
248358
unsafe { btck_block_count_transactions(self.inner) }
249359
}
250360

361+
pub fn header(&self) -> BlockHeader {
362+
unsafe { BlockHeader::from_ptr(btck_block_get_header(self.inner)) }
363+
}
364+
251365
/// Returns the transaction at the specified index.
252366
///
253367
/// # Arguments
@@ -864,6 +978,23 @@ mod tests {
864978

865979
test_owned_trait_requirements!(test_block_requirements, Block, btck_Block);
866980

981+
test_owned_trait_requirements!(
982+
test_block_header_requirements,
983+
BlockHeader,
984+
btck_BlockHeader
985+
);
986+
test_ref_trait_requirements!(
987+
test_block_header_ref_requirements,
988+
BlockHeaderRef<'static>,
989+
btck_BlockHeader
990+
);
991+
992+
test_owned_clone_and_send!(
993+
test_block_header_clone_send,
994+
Block::new(&read_block_data()[0]).unwrap().header(),
995+
Block::new(&read_block_data()[1]).unwrap()
996+
);
997+
867998
test_owned_trait_requirements!(
868999
test_block_spent_outputs_requirements,
8691000
BlockSpentOutputs,

src/core/block_tree_entry.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
use std::marker::PhantomData;
22

33
use libbitcoinkernel_sys::{
4-
btck_BlockTreeEntry, btck_block_tree_entry_get_block_hash, btck_block_tree_entry_get_height,
4+
btck_BlockTreeEntry, btck_block_tree_entry_get_block_hash,
5+
btck_block_tree_entry_get_block_header, btck_block_tree_entry_get_height,
56
btck_block_tree_entry_get_previous,
67
};
78

89
use crate::{
9-
core::block::BlockHashRef,
10+
core::block::{BlockHashRef, BlockHeaderRef},
1011
ffi::sealed::{AsPtr, FromPtr},
1112
ChainstateManager,
1213
};
@@ -44,6 +45,10 @@ impl<'a> BlockTreeEntry<'a> {
4445
unsafe { btck_block_tree_entry_get_height(self.inner) }
4546
}
4647

48+
pub fn header(&self) -> BlockHeaderRef<'_> {
49+
unsafe { BlockHeaderRef::from_ptr(btck_block_tree_entry_get_block_header(self.inner)) }
50+
}
51+
4752
/// Returns the current block hash associated with this BlockTreeEntry.
4853
pub fn block_hash(&self) -> BlockHashRef<'_> {
4954
let hash_ptr = unsafe { btck_block_tree_entry_get_block_hash(self.inner) };

src/notifications/types.rs

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ use std::marker::PhantomData;
22

33
use libbitcoinkernel_sys::{
44
btck_BlockValidationResult, btck_BlockValidationState, btck_SynchronizationState,
5-
btck_ValidationMode, btck_Warning, btck_block_validation_state_get_block_validation_result,
5+
btck_ValidationMode, btck_Warning, btck_block_validation_state_copy,
6+
btck_block_validation_state_create, btck_block_validation_state_destroy,
7+
btck_block_validation_state_get_block_validation_result,
68
btck_block_validation_state_get_validation_mode,
79
};
810

911
use crate::{
10-
ffi::sealed::{AsPtr, FromPtr},
12+
ffi::sealed::{AsPtr, FromMutPtr, FromPtr},
1113
BTCK_BLOCK_VALIDATION_RESULT_CACHED_INVALID, BTCK_BLOCK_VALIDATION_RESULT_CONSENSUS,
1214
BTCK_BLOCK_VALIDATION_RESULT_HEADER_LOW_WORK, BTCK_BLOCK_VALIDATION_RESULT_INVALID_HEADER,
1315
BTCK_BLOCK_VALIDATION_RESULT_INVALID_PREV, BTCK_BLOCK_VALIDATION_RESULT_MISSING_PREV,
@@ -191,6 +193,49 @@ pub trait BlockValidationStateExt: AsPtr<btck_BlockValidationState> {
191193
}
192194
}
193195

196+
pub struct BlockValidationState {
197+
inner: *mut btck_BlockValidationState,
198+
}
199+
200+
unsafe impl Send for BlockValidationState {}
201+
unsafe impl Sync for BlockValidationState {}
202+
203+
impl BlockValidationState {
204+
pub fn new() -> BlockValidationState {
205+
BlockValidationState {
206+
inner: unsafe { btck_block_validation_state_create() },
207+
}
208+
}
209+
}
210+
211+
impl AsPtr<btck_BlockValidationState> for BlockValidationState {
212+
fn as_ptr(&self) -> *const btck_BlockValidationState {
213+
self.inner as *const _
214+
}
215+
}
216+
217+
impl FromMutPtr<btck_BlockValidationState> for BlockValidationState {
218+
unsafe fn from_ptr(ptr: *mut btck_BlockValidationState) -> Self {
219+
BlockValidationState { inner: ptr }
220+
}
221+
}
222+
223+
impl BlockValidationStateExt for BlockValidationState {}
224+
225+
impl Clone for BlockValidationState {
226+
fn clone(&self) -> Self {
227+
BlockValidationState {
228+
inner: unsafe { btck_block_validation_state_copy(self.inner) },
229+
}
230+
}
231+
}
232+
233+
impl Drop for BlockValidationState {
234+
fn drop(&mut self) {
235+
unsafe { btck_block_validation_state_destroy(self.inner) }
236+
}
237+
}
238+
194239
pub struct BlockValidationStateRef<'a> {
195240
inner: *const btck_BlockValidationState,
196241
marker: PhantomData<&'a ()>,
@@ -228,10 +273,18 @@ impl<'a> BlockValidationStateExt for BlockValidationStateRef<'a> {}
228273
mod tests {
229274
use libbitcoinkernel_sys::btck_BlockValidationState;
230275

231-
use crate::ffi::test_utils::test_ref_trait_requirements;
276+
use crate::{
277+
ffi::test_utils::{test_owned_trait_requirements, test_ref_trait_requirements},
278+
notifications::types::{BlockValidationState, BlockValidationStateRef},
279+
};
232280

233281
use super::*;
234282

283+
test_owned_trait_requirements!(
284+
test_block_validation_state_requirements,
285+
BlockValidationState,
286+
btck_BlockValidationState
287+
);
235288
test_ref_trait_requirements!(
236289
test_block_validation_state_ref_requirements,
237290
BlockValidationStateRef<'static>,

src/state/chainstate.rs

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,26 @@
2828
use std::ffi::CString;
2929

3030
use libbitcoinkernel_sys::{
31-
btck_BlockHash, btck_ChainstateManager, btck_ChainstateManagerOptions, btck_block_read,
32-
btck_block_spent_outputs_read, btck_chainstate_manager_create, btck_chainstate_manager_destroy,
33-
btck_chainstate_manager_get_active_chain, btck_chainstate_manager_get_block_tree_entry_by_hash,
34-
btck_chainstate_manager_import_blocks, btck_chainstate_manager_options_create,
35-
btck_chainstate_manager_options_destroy, btck_chainstate_manager_options_set_wipe_dbs,
31+
btck_BlockHash, btck_BlockValidationState, btck_ChainstateManager,
32+
btck_ChainstateManagerOptions, btck_block_read, btck_block_spent_outputs_read,
33+
btck_chainstate_manager_create, btck_chainstate_manager_destroy,
34+
btck_chainstate_manager_get_active_chain, btck_chainstate_manager_get_best_entry,
35+
btck_chainstate_manager_get_block_tree_entry_by_hash, btck_chainstate_manager_import_blocks,
36+
btck_chainstate_manager_options_create, btck_chainstate_manager_options_destroy,
37+
btck_chainstate_manager_options_set_wipe_dbs,
3638
btck_chainstate_manager_options_set_worker_threads_num,
3739
btck_chainstate_manager_options_update_block_tree_db_in_memory,
3840
btck_chainstate_manager_options_update_chainstate_db_in_memory,
39-
btck_chainstate_manager_process_block,
41+
btck_chainstate_manager_process_block, btck_chainstate_manager_process_block_header,
4042
};
4143

4244
use crate::{
45+
core::block::BlockHeader,
4346
ffi::{
4447
c_helpers,
4548
sealed::{AsPtr, FromMutPtr, FromPtr},
4649
},
50+
notifications::types::BlockValidationState,
4751
Block, BlockHash, BlockSpentOutputs, BlockTreeEntry, KernelError,
4852
};
4953

@@ -253,6 +257,18 @@ impl ChainstateManager {
253257
}
254258
}
255259

260+
pub fn process_header(&self, header: &BlockHeader) -> (bool, BlockValidationState) {
261+
let state = BlockValidationState::new();
262+
let accepted = unsafe {
263+
btck_chainstate_manager_process_block_header(
264+
self.inner,
265+
header.as_ptr(),
266+
state.as_ptr() as *mut btck_BlockValidationState,
267+
)
268+
};
269+
(c_helpers::success(accepted), state)
270+
}
271+
256272
/// Initialize the chainstate manager and optionally trigger a reindex.
257273
///
258274
/// This should be called after creating the chainstate manager to complete
@@ -347,6 +363,15 @@ impl ChainstateManager {
347363
unsafe { Chain::from_ptr(ptr) }
348364
}
349365

366+
pub fn best_entry(&self) -> Option<BlockTreeEntry<'_>> {
367+
let ptr = unsafe { btck_chainstate_manager_get_best_entry(self.inner) };
368+
if ptr.is_null() {
369+
None
370+
} else {
371+
Some(unsafe { BlockTreeEntry::from_ptr(ptr) })
372+
}
373+
}
374+
350375
/// Get a block tree entry by its block hash.
351376
///
352377
/// Looks up a block in the block tree using its hash. The block tree contains

0 commit comments

Comments
 (0)