Skip to content

Commit 358f3b4

Browse files
committed
Add header handling
1 parent b524379 commit 358f3b4

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
@@ -109,11 +109,13 @@ use std::{
109109
};
110110

111111
use libbitcoinkernel_sys::{
112-
btck_Block, btck_BlockHash, btck_BlockSpentOutputs, btck_Coin, btck_TransactionSpentOutputs,
113-
btck_block_copy, btck_block_count_transactions, btck_block_create, btck_block_destroy,
114-
btck_block_get_hash, btck_block_get_transaction_at, btck_block_hash_copy,
115-
btck_block_hash_create, btck_block_hash_destroy, btck_block_hash_equals,
116-
btck_block_hash_to_bytes, btck_block_spent_outputs_copy, btck_block_spent_outputs_count,
112+
btck_Block, btck_BlockHash, btck_BlockHeader, btck_BlockSpentOutputs, btck_Coin,
113+
btck_TransactionSpentOutputs, btck_block_copy, btck_block_count_transactions,
114+
btck_block_create, btck_block_destroy, btck_block_get_hash, btck_block_get_header,
115+
btck_block_get_transaction_at, btck_block_hash_copy, btck_block_hash_create,
116+
btck_block_hash_destroy, btck_block_hash_equals, btck_block_hash_to_bytes,
117+
btck_block_header_copy, btck_block_header_create, btck_block_header_destroy,
118+
btck_block_header_get_hash, btck_block_spent_outputs_copy, btck_block_spent_outputs_count,
117119
btck_block_spent_outputs_destroy, btck_block_spent_outputs_get_transaction_spent_outputs_at,
118120
btck_block_to_bytes, btck_coin_confirmation_height, btck_coin_copy, btck_coin_destroy,
119121
btck_coin_get_output, btck_coin_is_coinbase, btck_transaction_spent_outputs_copy,
@@ -270,6 +272,15 @@ impl AsPtr<btck_BlockHash> for BlockHash {
270272
}
271273
}
272274

275+
impl<'a> FromPtr<btck_BlockHash> for BlockHashRef<'a> {
276+
unsafe fn from_ptr(ptr: *const btck_BlockHash) -> Self {
277+
BlockHashRef {
278+
inner: ptr,
279+
marker: PhantomData,
280+
}
281+
}
282+
}
283+
273284
impl FromMutPtr<btck_BlockHash> for BlockHash {
274285
unsafe fn from_ptr(ptr: *mut btck_BlockHash) -> Self {
275286
BlockHash { inner: ptr }
@@ -377,15 +388,6 @@ impl<'a> AsPtr<btck_BlockHash> for BlockHashRef<'a> {
377388
}
378389
}
379390

380-
impl<'a> FromPtr<btck_BlockHash> for BlockHashRef<'a> {
381-
unsafe fn from_ptr(ptr: *const btck_BlockHash) -> Self {
382-
BlockHashRef {
383-
inner: ptr,
384-
marker: PhantomData,
385-
}
386-
}
387-
}
388-
389391
impl<'a> BlockHashExt for BlockHashRef<'a> {}
390392

391393
impl<'a> Clone for BlockHashRef<'a> {
@@ -420,6 +422,114 @@ impl<'a> Eq for BlockHashRef<'a> {}
420422

421423
impl<'a> Copy for BlockHashRef<'a> {}
422424

425+
/// Common operations for block headers, implemented by both owned and borrow types.
426+
pub trait BlockHeaderExt: AsPtr<btck_BlockHeader> {
427+
/// Return the block hash of the header.
428+
fn hash(&self) -> BlockHash {
429+
unsafe { BlockHash::from_ptr(btck_block_header_get_hash(self.as_ptr())) }
430+
}
431+
}
432+
433+
/// A Bitcoin block header.
434+
///
435+
/// Block headers can be created from raw serialized data or retrieved from the
436+
/// chain or blocks.
437+
pub struct BlockHeader {
438+
inner: *mut btck_BlockHeader,
439+
}
440+
441+
unsafe impl Send for BlockHeader {}
442+
unsafe impl Sync for BlockHeader {}
443+
444+
impl BlockHeader {
445+
pub fn new(header_bytes: &[u8]) -> Result<Self, KernelError> {
446+
let inner = unsafe {
447+
btck_block_header_create(header_bytes.as_ptr() as *const c_void, header_bytes.len())
448+
};
449+
450+
if inner.is_null() {
451+
Err(KernelError::Internal(
452+
"Failed to create header from bytes".to_string(),
453+
))
454+
} else {
455+
Ok(BlockHeader { inner })
456+
}
457+
}
458+
459+
pub fn as_ref(&self) -> BlockHeaderRef<'_> {
460+
unsafe { BlockHeaderRef::from_ptr(self.inner as *const _) }
461+
}
462+
}
463+
464+
impl FromMutPtr<btck_BlockHeader> for BlockHeader {
465+
unsafe fn from_ptr(ptr: *mut btck_BlockHeader) -> Self {
466+
BlockHeader { inner: ptr }
467+
}
468+
}
469+
470+
impl AsPtr<btck_BlockHeader> for BlockHeader {
471+
fn as_ptr(&self) -> *const btck_BlockHeader {
472+
self.inner as *const _
473+
}
474+
}
475+
476+
impl BlockHeaderExt for BlockHeader {}
477+
478+
impl Clone for BlockHeader {
479+
fn clone(&self) -> Self {
480+
BlockHeader {
481+
inner: unsafe { btck_block_header_copy(self.inner) },
482+
}
483+
}
484+
}
485+
486+
impl Drop for BlockHeader {
487+
fn drop(&mut self) {
488+
unsafe { btck_block_header_destroy(self.inner) }
489+
}
490+
}
491+
492+
pub struct BlockHeaderRef<'a> {
493+
inner: *const btck_BlockHeader,
494+
marker: PhantomData<&'a ()>,
495+
}
496+
497+
unsafe impl<'a> Send for BlockHeaderRef<'a> {}
498+
unsafe impl<'a> Sync for BlockHeaderRef<'a> {}
499+
500+
impl<'a> BlockHeaderRef<'a> {
501+
pub fn to_owned(&self) -> BlockHeader {
502+
BlockHeader {
503+
inner: unsafe { btck_block_header_copy(self.inner) },
504+
}
505+
}
506+
}
507+
508+
impl<'a> AsPtr<btck_BlockHeader> for BlockHeaderRef<'a> {
509+
fn as_ptr(&self) -> *const btck_BlockHeader {
510+
self.inner
511+
}
512+
}
513+
514+
impl<'a> FromPtr<btck_BlockHeader> for BlockHeaderRef<'a> {
515+
unsafe fn from_ptr(ptr: *const btck_BlockHeader) -> Self {
516+
BlockHeaderRef {
517+
inner: ptr,
518+
marker: PhantomData,
519+
}
520+
}
521+
}
522+
523+
impl<'a> BlockHeaderExt for BlockHeaderRef<'a> {}
524+
525+
impl<'a> Copy for BlockHeaderRef<'a> {}
526+
527+
impl<'a> Clone for BlockHeaderRef<'a> {
528+
fn clone(&self) -> Self {
529+
*self
530+
}
531+
}
532+
423533
/// A block containing a header and transactions.
424534
///
425535
/// Blocks are the fundamental units of the block chain, linking together
@@ -542,6 +652,10 @@ impl Block {
542652
unsafe { btck_block_count_transactions(self.inner) }
543653
}
544654

655+
pub fn header(&self) -> BlockHeader {
656+
unsafe { BlockHeader::from_ptr(btck_block_get_header(self.inner)) }
657+
}
658+
545659
/// Returns a reference to the transaction at the specified index.
546660
///
547661
/// # Arguments
@@ -1574,6 +1688,23 @@ mod tests {
15741688

15751689
test_owned_trait_requirements!(test_block_requirements, Block, btck_Block);
15761690

1691+
test_owned_trait_requirements!(
1692+
test_block_header_requirements,
1693+
BlockHeader,
1694+
btck_BlockHeader
1695+
);
1696+
test_ref_trait_requirements!(
1697+
test_block_header_ref_requirements,
1698+
BlockHeaderRef<'static>,
1699+
btck_BlockHeader
1700+
);
1701+
1702+
test_owned_clone_and_send!(
1703+
test_block_header_clone_send,
1704+
Block::new(&read_block_data()[0]).unwrap().header(),
1705+
Block::new(&read_block_data()[1]).unwrap()
1706+
);
1707+
15771708
test_owned_trait_requirements!(
15781709
test_block_spent_outputs_requirements,
15791710
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)