|
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, |
@@ -72,6 +74,15 @@ impl AsPtr<btck_BlockHash> for BlockHash { |
72 | 74 | } |
73 | 75 | } |
74 | 76 |
|
| 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 | + |
75 | 86 | impl FromMutPtr<btck_BlockHash> for BlockHash { |
76 | 87 | unsafe fn from_ptr(ptr: *mut btck_BlockHash) -> Self { |
77 | 88 | BlockHash { inner: ptr } |
@@ -166,15 +177,6 @@ impl<'a> AsPtr<btck_BlockHash> for BlockHashRef<'a> { |
166 | 177 | } |
167 | 178 | } |
168 | 179 |
|
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 | | - |
178 | 180 | impl<'a> BlockHashExt for BlockHashRef<'a> {} |
179 | 181 |
|
180 | 182 | impl<'a> Clone for BlockHashRef<'a> { |
@@ -209,6 +211,114 @@ impl<'a> Eq for BlockHashRef<'a> {} |
209 | 211 |
|
210 | 212 | impl<'a> Copy for BlockHashRef<'a> {} |
211 | 213 |
|
| 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 | + |
212 | 322 | /// A Bitcoin block containing a header and transactions. |
213 | 323 | /// |
214 | 324 | /// Blocks can be created from raw serialized data or retrieved from the blockchain. |
@@ -248,6 +358,10 @@ impl Block { |
248 | 358 | unsafe { btck_block_count_transactions(self.inner) } |
249 | 359 | } |
250 | 360 |
|
| 361 | + pub fn header(&self) -> BlockHeader { |
| 362 | + unsafe { BlockHeader::from_ptr(btck_block_get_header(self.inner)) } |
| 363 | + } |
| 364 | + |
251 | 365 | /// Returns the transaction at the specified index. |
252 | 366 | /// |
253 | 367 | /// # Arguments |
@@ -864,6 +978,23 @@ mod tests { |
864 | 978 |
|
865 | 979 | test_owned_trait_requirements!(test_block_requirements, Block, btck_Block); |
866 | 980 |
|
| 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 | + |
867 | 998 | test_owned_trait_requirements!( |
868 | 999 | test_block_spent_outputs_requirements, |
869 | 1000 | BlockSpentOutputs, |
|
0 commit comments