Skip to content

Commit 9ebf391

Browse files
committed
Add header handling
1 parent 73bfc64 commit 9ebf391

File tree

5 files changed

+255
-28
lines changed

5 files changed

+255
-28
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,
@@ -68,6 +70,15 @@ impl AsPtr<btck_BlockHash> for BlockHash {
6870
}
6971
}
7072

73+
impl<'a> FromPtr<btck_BlockHash> for BlockHashRef<'a> {
74+
unsafe fn from_ptr(ptr: *const btck_BlockHash) -> Self {
75+
BlockHashRef {
76+
inner: ptr,
77+
marker: PhantomData,
78+
}
79+
}
80+
}
81+
7182
impl FromMutPtr<btck_BlockHash> for BlockHash {
7283
unsafe fn from_ptr(ptr: *mut btck_BlockHash) -> Self {
7384
BlockHash { inner: ptr }
@@ -162,15 +173,6 @@ impl<'a> AsPtr<btck_BlockHash> for BlockHashRef<'a> {
162173
}
163174
}
164175

165-
impl<'a> FromPtr<btck_BlockHash> for BlockHashRef<'a> {
166-
unsafe fn from_ptr(ptr: *const btck_BlockHash) -> Self {
167-
BlockHashRef {
168-
inner: ptr,
169-
marker: PhantomData,
170-
}
171-
}
172-
}
173-
174176
impl<'a> BlockHashExt for BlockHashRef<'a> {}
175177

176178
impl<'a> Clone for BlockHashRef<'a> {
@@ -205,6 +207,114 @@ impl<'a> Eq for BlockHashRef<'a> {}
205207

206208
impl<'a> Copy for BlockHashRef<'a> {}
207209

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

357+
pub fn header(&self) -> BlockHeader {
358+
unsafe { BlockHeader::from_ptr(btck_block_get_header(self.inner)) }
359+
}
360+
247361
/// Returns the transaction at the specified index.
248362
///
249363
/// # Arguments
@@ -866,6 +980,23 @@ mod tests {
866980

867981
test_owned_trait_requirements!(test_block_requirements, Block, btck_Block);
868982

983+
test_owned_trait_requirements!(
984+
test_block_header_requirements,
985+
BlockHeader,
986+
btck_BlockHeader
987+
);
988+
test_ref_trait_requirements!(
989+
test_block_header_ref_requirements,
990+
BlockHeaderRef<'static>,
991+
btck_BlockHeader
992+
);
993+
994+
test_owned_clone_and_send!(
995+
test_block_header_clone_send,
996+
Block::new(&read_block_data()[0]).unwrap().header(),
997+
Block::new(&read_block_data()[1]).unwrap()
998+
);
999+
8691000
test_owned_trait_requirements!(
8701001
test_block_spent_outputs_requirements,
8711002
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: 54 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 ()>,
@@ -229,11 +274,17 @@ mod tests {
229274
use libbitcoinkernel_sys::btck_BlockValidationState;
230275

231276
use crate::{
232-
ffi::test_utils::test_ref_trait_requirements, notifications::types::BlockValidationStateRef,
277+
ffi::test_utils::{test_owned_trait_requirements, test_ref_trait_requirements},
278+
notifications::types::{BlockValidationState, BlockValidationStateRef},
233279
};
234280

235281
use super::*;
236282

283+
test_owned_trait_requirements!(
284+
test_block_validation_state_requirements,
285+
BlockValidationState,
286+
btck_BlockValidationState
287+
);
237288
test_ref_trait_requirements!(
238289
test_block_validation_state_ref_requirements,
239290
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)