|
1 | 1 | use std::{ffi::c_void, marker::PhantomData}; |
2 | 2 |
|
3 | 3 | 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, |
9 | 11 | btck_block_spent_outputs_destroy, btck_block_spent_outputs_get_transaction_spent_outputs_at, |
10 | 12 | btck_block_to_bytes, btck_coin_confirmation_height, btck_coin_copy, btck_coin_destroy, |
11 | 13 | btck_coin_get_output, btck_coin_is_coinbase, btck_transaction_spent_outputs_copy, |
@@ -68,6 +70,15 @@ impl AsPtr<btck_BlockHash> for BlockHash { |
68 | 70 | } |
69 | 71 | } |
70 | 72 |
|
| 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 | + |
71 | 82 | impl FromMutPtr<btck_BlockHash> for BlockHash { |
72 | 83 | unsafe fn from_ptr(ptr: *mut btck_BlockHash) -> Self { |
73 | 84 | BlockHash { inner: ptr } |
@@ -162,15 +173,6 @@ impl<'a> AsPtr<btck_BlockHash> for BlockHashRef<'a> { |
162 | 173 | } |
163 | 174 | } |
164 | 175 |
|
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 | | - |
174 | 176 | impl<'a> BlockHashExt for BlockHashRef<'a> {} |
175 | 177 |
|
176 | 178 | impl<'a> Clone for BlockHashRef<'a> { |
@@ -205,6 +207,114 @@ impl<'a> Eq for BlockHashRef<'a> {} |
205 | 207 |
|
206 | 208 | impl<'a> Copy for BlockHashRef<'a> {} |
207 | 209 |
|
| 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 | + |
208 | 318 | /// A Bitcoin block containing a header and transactions. |
209 | 319 | /// |
210 | 320 | /// Blocks can be created from raw serialized data or retrieved from the blockchain. |
@@ -244,6 +354,10 @@ impl Block { |
244 | 354 | unsafe { btck_block_count_transactions(self.inner) } |
245 | 355 | } |
246 | 356 |
|
| 357 | + pub fn header(&self) -> BlockHeader { |
| 358 | + unsafe { BlockHeader::from_ptr(btck_block_get_header(self.inner)) } |
| 359 | + } |
| 360 | + |
247 | 361 | /// Returns the transaction at the specified index. |
248 | 362 | /// |
249 | 363 | /// # Arguments |
@@ -866,6 +980,23 @@ mod tests { |
866 | 980 |
|
867 | 981 | test_owned_trait_requirements!(test_block_requirements, Block, btck_Block); |
868 | 982 |
|
| 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 | + |
869 | 1000 | test_owned_trait_requirements!( |
870 | 1001 | test_block_spent_outputs_requirements, |
871 | 1002 | BlockSpentOutputs, |
|
0 commit comments