bitcoinkernel/
lib.rs

1#![allow(non_upper_case_globals)]
2#![allow(non_camel_case_types)]
3#![allow(non_snake_case)]
4
5use std::ffi::{CString, NulError};
6use std::fmt;
7use std::marker::PhantomData;
8use std::os::raw::{c_char, c_void};
9use std::sync::Arc;
10
11use libbitcoinkernel_sys::*;
12
13pub const VERIFY_NONE: u32 = kernel_ScriptFlags_kernel_SCRIPT_FLAGS_VERIFY_NONE;
14pub const VERIFY_P2SH: u32 = kernel_ScriptFlags_kernel_SCRIPT_FLAGS_VERIFY_P2SH;
15pub const VERIFY_DERSIG: u32 = kernel_ScriptFlags_kernel_SCRIPT_FLAGS_VERIFY_DERSIG;
16pub const VERIFY_NULLDUMMY: u32 = kernel_ScriptFlags_kernel_SCRIPT_FLAGS_VERIFY_NULLDUMMY;
17pub const VERIFY_CHECKLOCKTIMEVERIFY: u32 =
18    kernel_ScriptFlags_kernel_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY;
19pub const VERIFY_CHECKSEQUENCEVERIFY: u32 =
20    kernel_ScriptFlags_kernel_SCRIPT_FLAGS_VERIFY_CHECKSEQUENCEVERIFY;
21pub const VERIFY_WITNESS: u32 = kernel_ScriptFlags_kernel_SCRIPT_FLAGS_VERIFY_WITNESS;
22pub const VERIFY_TAPROOT: u32 = kernel_ScriptFlags_kernel_SCRIPT_FLAGS_VERIFY_TAPROOT;
23pub const VERIFY_ALL_PRE_TAPROOT: u32 = VERIFY_P2SH
24    | VERIFY_DERSIG
25    | VERIFY_NULLDUMMY
26    | VERIFY_CHECKLOCKTIMEVERIFY
27    | VERIFY_CHECKSEQUENCEVERIFY
28    | VERIFY_WITNESS;
29
30/// Verifies a transaction input against its corresponding output script.
31///
32/// # Arguments
33/// * `script_pubkey` - The output script to verify against
34/// * `amount` - Needs to be set if the segwit flag is set
35/// * `tx_to` - The transaction containing the input to verify
36/// * `input_index` - The index of the input within `tx_to` to verify
37/// * `flags` - Defaults to all if none
38/// * `spent_output` - The outputs being spent by this transaction
39///
40/// # Returns
41/// * `Ok(())` if verification succeeds
42/// * [`KernelError::ScriptVerify`] an error describing the failure
43pub fn verify(
44    script_pubkey: &ScriptPubkey,
45    amount: Option<i64>,
46    tx_to: &Transaction,
47    input_index: u32,
48    flags: Option<u32>,
49    spent_outputs: &[TxOut],
50) -> Result<(), KernelError> {
51    let kernel_flags = if let Some(flag) = flags {
52        flag
53    } else {
54        kernel_ScriptFlags_kernel_SCRIPT_FLAGS_VERIFY_ALL
55    };
56    let mut status = kernel_ScriptVerifyStatus_kernel_SCRIPT_VERIFY_OK;
57    let kernel_amount = if let Some(a) = amount { a } else { 0 };
58    let kernel_spent_outputs: Vec<*const kernel_TransactionOutput> = spent_outputs
59        .iter()
60        .map(|utxo| utxo.inner as *const kernel_TransactionOutput)
61        .collect();
62
63    let spent_outputs_ptr = if kernel_spent_outputs.is_empty() {
64        std::ptr::null_mut()
65    } else {
66        kernel_spent_outputs.as_ptr() as *mut *const kernel_TransactionOutput
67    };
68
69    let ret = unsafe {
70        kernel_verify_script(
71            script_pubkey.inner,
72            kernel_amount,
73            tx_to.inner,
74            spent_outputs_ptr,
75            spent_outputs.len(),
76            input_index,
77            kernel_flags,
78            &mut status,
79        )
80    };
81
82    if !ret {
83        let err = match status {
84            kernel_ScriptVerifyStatus_kernel_SCRIPT_VERIFY_ERROR_TX_INPUT_INDEX => {
85                ScriptVerifyError::TxInputIndex
86            }
87            kernel_ScriptVerifyStatus_kernel_SCRIPT_VERIFY_ERROR_INVALID_FLAGS => {
88                ScriptVerifyError::InvalidFlags
89            }
90            kernel_ScriptVerifyStatus_kernel_SCRIPT_VERIFY_ERROR_INVALID_FLAGS_COMBINATION => {
91                ScriptVerifyError::InvalidFlagsCombination
92            }
93            kernel_ScriptVerifyStatus_kernel_SCRIPT_VERIFY_ERROR_SPENT_OUTPUTS_REQUIRED => {
94                ScriptVerifyError::SpentOutputsRequired
95            }
96            kernel_ScriptVerifyStatus_kernel_SCRIPT_VERIFY_ERROR_SPENT_OUTPUTS_MISMATCH => {
97                ScriptVerifyError::SpentOutputsMismatch
98            }
99            _ => ScriptVerifyError::Invalid,
100        };
101        Err(KernelError::ScriptVerify(err))
102    } else {
103        Ok(())
104    }
105}
106
107unsafe fn cast_string(c_str: *const c_char, len: usize) -> String {
108    if !c_str.is_null() {
109        let slice = std::slice::from_raw_parts(c_str as *const u8, len);
110        String::from_utf8_lossy(slice).into_owned()
111    } else {
112        "".to_string()
113    }
114}
115
116/// The current synch state, i.e. whether in reindex, ibd, or complete.
117/// Emitted by the block tip notification.
118#[derive(Debug)]
119pub enum SynchronizationState {
120    INIT_REINDEX,
121    INIT_DOWNLOAD,
122    POST_INIT,
123}
124
125impl From<kernel_SynchronizationState> for SynchronizationState {
126    fn from(state: kernel_SynchronizationState) -> SynchronizationState {
127        match state {
128            kernel_SynchronizationState_kernel_INIT_DOWNLOAD => SynchronizationState::INIT_DOWNLOAD,
129            kernel_SynchronizationState_kernel_INIT_REINDEX => SynchronizationState::INIT_REINDEX,
130            kernel_SynchronizationState_kernel_POST_INIT => SynchronizationState::POST_INIT,
131            _ => panic!("Unexpected Synchronization state"),
132        }
133    }
134}
135
136/// Warning state emitted by the kernel warning notification.
137pub enum KernelWarning {
138    UNKNOWN_NEW_RULES_ACTIVATED,
139    LARGE_WORK_INVALID_CHAIN,
140}
141
142impl From<kernel_Warning> for KernelWarning {
143    fn from(warning: kernel_Warning) -> KernelWarning {
144        match warning {
145            kernel_Warning_kernel_UNKNOWN_NEW_RULES_ACTIVATED => {
146                KernelWarning::UNKNOWN_NEW_RULES_ACTIVATED
147            }
148            kernel_Warning_kernel_LARGE_WORK_INVALID_CHAIN => {
149                KernelWarning::LARGE_WORK_INVALID_CHAIN
150            }
151            _ => panic!("Unexpected kernel warning"),
152        }
153    }
154}
155
156/// The ChainType used to configure the kernel [`Context`].
157pub enum ChainType {
158    MAINNET,
159    TESTNET,
160    SIGNET,
161    REGTEST,
162}
163
164impl From<ChainType> for kernel_ChainType {
165    fn from(chain: ChainType) -> kernel_ChainType {
166        match chain {
167            ChainType::MAINNET => kernel_ChainType_kernel_CHAIN_TYPE_MAINNET,
168            ChainType::TESTNET => kernel_ChainType_kernel_CHAIN_TYPE_TESTNET,
169            ChainType::SIGNET => kernel_ChainType_kernel_CHAIN_TYPE_SIGNET,
170            ChainType::REGTEST => kernel_ChainType_kernel_CHAIN_TYPE_REGTEST,
171        }
172    }
173}
174
175/// The chain's tip was updated to the provided block hash.
176pub trait BlockTip: Fn(SynchronizationState, BlockHash) {}
177impl<F: Fn(SynchronizationState, BlockHash)> BlockTip for F {}
178
179/// A new best block header was added.
180pub trait HeaderTip: Fn(SynchronizationState, i64, i64, bool) {}
181impl<F: Fn(SynchronizationState, i64, i64, bool)> HeaderTip for F {}
182
183/// Reports on the current synchronization progress.
184pub trait Progress: Fn(String, i32, bool) {}
185impl<F: Fn(String, i32, bool)> Progress for F {}
186
187/// A warning state issued by the kernel during validation.
188pub trait WarningSet: Fn(KernelWarning, String) {}
189impl<F: Fn(KernelWarning, String)> WarningSet for F {}
190
191/// A previous condition leading to the issuance of a warning is no longer given.
192pub trait WarningUnset: Fn(KernelWarning) {}
193impl<F: Fn(KernelWarning)> WarningUnset for F {}
194
195/// An error was encountered when flushing data to disk.
196pub trait FlushError: Fn(String) {}
197impl<F: Fn(String)> FlushError for F {}
198
199/// An un-recoverable system error was encountered by the library.
200pub trait FatalError: Fn(String) {}
201impl<F: Fn(String)> FatalError for F {}
202
203/// A callback holder struct for the notification interface calls.
204pub struct KernelNotificationInterfaceCallbacks {
205    pub kn_block_tip: Box<dyn BlockTip>,
206    pub kn_header_tip: Box<dyn HeaderTip>,
207    pub kn_progress: Box<dyn Progress>,
208    pub kn_warning_set: Box<dyn WarningSet>,
209    pub kn_warning_unset: Box<dyn WarningUnset>,
210    pub kn_flush_error: Box<dyn FlushError>,
211    pub kn_fatal_error: Box<dyn FatalError>,
212}
213
214unsafe extern "C" fn kn_block_tip_wrapper(
215    user_data: *mut c_void,
216    state: kernel_SynchronizationState,
217    block_index: *const kernel_BlockIndex,
218) {
219    let holder = &*(user_data as *mut KernelNotificationInterfaceCallbacks);
220    let hash = kernel_block_index_get_block_hash(block_index);
221    let res = BlockHash {
222        hash: (&*hash).hash,
223    };
224    kernel_block_hash_destroy(hash);
225    (holder.kn_block_tip)(state.into(), res);
226}
227
228unsafe extern "C" fn kn_header_tip_wrapper(
229    user_data: *mut c_void,
230    state: kernel_SynchronizationState,
231    height: i64,
232    timestamp: i64,
233    presync: bool,
234) {
235    let holder = &*(user_data as *mut KernelNotificationInterfaceCallbacks);
236    (holder.kn_header_tip)(state.into(), height, timestamp, presync);
237}
238
239unsafe extern "C" fn kn_progress_wrapper(
240    user_data: *mut c_void,
241    title: *const c_char,
242    title_len: usize,
243    progress_percent: i32,
244    resume_possible: bool,
245) {
246    let holder = &*(user_data as *mut KernelNotificationInterfaceCallbacks);
247    (holder.kn_progress)(
248        cast_string(title, title_len),
249        progress_percent,
250        resume_possible,
251    );
252}
253
254unsafe extern "C" fn kn_warning_set_wrapper(
255    user_data: *mut c_void,
256    warning: kernel_Warning,
257    message: *const c_char,
258    message_len: usize,
259) {
260    let holder = &*(user_data as *mut KernelNotificationInterfaceCallbacks);
261    (holder.kn_warning_set)(warning.into(), cast_string(message, message_len));
262}
263
264unsafe extern "C" fn kn_warning_unset_wrapper(user_data: *mut c_void, warning: kernel_Warning) {
265    let holder = &*(user_data as *mut KernelNotificationInterfaceCallbacks);
266    (holder.kn_warning_unset)(warning.into());
267}
268
269unsafe extern "C" fn kn_flush_error_wrapper(
270    user_data: *mut c_void,
271    message: *const c_char,
272    message_len: usize,
273) {
274    let holder = &*(user_data as *mut KernelNotificationInterfaceCallbacks);
275    (holder.kn_flush_error)(cast_string(message, message_len));
276}
277
278unsafe extern "C" fn kn_fatal_error_wrapper(
279    user_data: *mut c_void,
280    message: *const c_char,
281    message_len: usize,
282) {
283    let holder = &*(user_data as *mut KernelNotificationInterfaceCallbacks);
284    (holder.kn_fatal_error)(cast_string(message, message_len));
285}
286
287/// The chain parameters with which to configure a [`Context`].
288pub struct ChainParams {
289    inner: *mut kernel_ChainParameters,
290}
291
292unsafe impl Send for ChainParams {}
293unsafe impl Sync for ChainParams {}
294
295impl ChainParams {
296    pub fn new(chain_type: ChainType) -> ChainParams {
297        let kernel_chain_type = chain_type.into();
298        ChainParams {
299            inner: unsafe { kernel_chain_parameters_create(kernel_chain_type) },
300        }
301    }
302}
303
304impl Drop for ChainParams {
305    fn drop(&mut self) {
306        unsafe {
307            kernel_chain_parameters_destroy(self.inner);
308        }
309    }
310}
311
312/// Exposes the result after validating a block.
313pub trait BlockChecked: Fn(UnownedBlock, ValidationMode, BlockValidationResult) {}
314impl<F: Fn(UnownedBlock, ValidationMode, BlockValidationResult)> BlockChecked for F {}
315
316/// A holder struct for validation interface callbacks
317pub struct ValidationInterfaceCallbacks {
318    /// Called after a block has completed validation and communicates its validation state.
319    pub block_checked: Box<dyn BlockChecked>,
320}
321
322unsafe extern "C" fn vi_block_checked_wrapper(
323    user_data: *mut c_void,
324    block: *const kernel_BlockPointer,
325    stateIn: *const kernel_BlockValidationState,
326) {
327    let holder = &*(user_data as *mut ValidationInterfaceCallbacks);
328    let result = kernel_get_block_validation_result_from_block_validation_state(stateIn);
329    let mode = kernel_get_validation_mode_from_block_validation_state(stateIn);
330    (holder.block_checked)(UnownedBlock::new(block), mode.into(), result.into());
331}
332
333/// The main context struct. This should be setup through the [`ContextBuilder`] and
334/// has to be kept in memory for the duration of context-dependent library
335/// operations.
336///
337pub struct Context {
338    inner: *mut kernel_Context,
339    // We need something to hold this in memory.
340    #[allow(dead_code)]
341    kn_callbacks: Option<Box<KernelNotificationInterfaceCallbacks>>,
342    #[allow(dead_code)]
343    vi_callbacks: Option<Box<ValidationInterfaceCallbacks>>,
344}
345
346unsafe impl Send for Context {}
347unsafe impl Sync for Context {}
348
349impl Context {
350    pub fn interrupt(&self) -> bool {
351        unsafe { kernel_context_interrupt(self.inner) }
352    }
353}
354
355impl Drop for Context {
356    fn drop(&mut self) {
357        unsafe {
358            kernel_context_destroy(self.inner);
359        }
360    }
361}
362
363/// Builder struct for the kernel [`Context`].
364///
365/// The builder by default configures for mainnet and swallows any kernel
366/// notifications.
367pub struct ContextBuilder {
368    inner: *mut kernel_ContextOptions,
369    kn_callbacks: Option<Box<KernelNotificationInterfaceCallbacks>>,
370    vi_callbacks: Option<Box<ValidationInterfaceCallbacks>>,
371}
372
373impl ContextBuilder {
374    pub fn new() -> ContextBuilder {
375        let context = ContextBuilder {
376            inner: unsafe { kernel_context_options_create() },
377            kn_callbacks: None,
378            vi_callbacks: None,
379        };
380        context
381    }
382
383    /// Consumes the builder and creates a [`Context`].
384    ///
385    /// # Errors
386    ///
387    /// Returns [`KernelError::Internal`] if [`Context`] creation fails.
388    pub fn build(self) -> Result<Context, KernelError> {
389        let inner = unsafe { kernel_context_create(self.inner) };
390        if inner.is_null() {
391            return Err(KernelError::Internal("Invalid context.".to_string()));
392        }
393        unsafe { kernel_context_options_destroy(self.inner) };
394        Ok(Context {
395            inner,
396            kn_callbacks: self.kn_callbacks,
397            vi_callbacks: self.vi_callbacks,
398        })
399    }
400
401    /// Sets the notifications callbacks to the passed in holder struct
402    pub fn kn_callbacks(
403        mut self,
404        kn_callbacks: Box<KernelNotificationInterfaceCallbacks>,
405    ) -> ContextBuilder {
406        let kn_pointer = Box::into_raw(kn_callbacks);
407        unsafe {
408            let holder = kernel_NotificationInterfaceCallbacks {
409                user_data: kn_pointer as *mut c_void,
410                block_tip: Some(kn_block_tip_wrapper),
411                header_tip: Some(kn_header_tip_wrapper),
412                progress: Some(kn_progress_wrapper),
413                warning_set: Some(kn_warning_set_wrapper),
414                warning_unset: Some(kn_warning_unset_wrapper),
415                flush_error: Some(kn_flush_error_wrapper),
416                fatal_error: Some(kn_fatal_error_wrapper),
417            };
418            kernel_context_options_set_notifications(self.inner, holder);
419        };
420        self.kn_callbacks = unsafe { Some(Box::from_raw(kn_pointer)) };
421        self
422    }
423
424    /// Sets the chain type
425    pub fn chain_type(self, chain_type: ChainType) -> ContextBuilder {
426        let chain_params = ChainParams::new(chain_type);
427        unsafe { kernel_context_options_set_chainparams(self.inner, chain_params.inner) };
428        self
429    }
430
431    /// Sets the validation interface callbacks
432    pub fn validation_interface(
433        mut self,
434        vi_callbacks: Box<ValidationInterfaceCallbacks>,
435    ) -> ContextBuilder {
436        let vi_pointer = Box::into_raw(vi_callbacks);
437        unsafe {
438            let holder = kernel_ValidationInterfaceCallbacks {
439                user_data: vi_pointer as *mut c_void,
440                block_checked: Some(vi_block_checked_wrapper),
441            };
442            kernel_context_options_set_validation_interface(self.inner, holder);
443        }
444        self.vi_callbacks = unsafe { Some(Box::from_raw(vi_pointer)) };
445        self
446    }
447}
448
449/// A collection of errors emitted by this library
450#[derive(Debug)]
451pub enum KernelError {
452    Internal(String),
453    CStringCreationFailed(String),
454    InvalidOptions(String),
455    OutOfBounds,
456    ScriptVerify(ScriptVerifyError),
457}
458
459/// A collection of errors that may occur during script verification
460#[derive(Debug)]
461pub enum ScriptVerifyError {
462    TxInputIndex,
463    TxSizeMismatch,
464    TxDeserialize,
465    InvalidFlags,
466    InvalidFlagsCombination,
467    SpentOutputsMismatch,
468    SpentOutputsRequired,
469    Invalid,
470}
471
472impl From<NulError> for KernelError {
473    fn from(err: NulError) -> Self {
474        KernelError::CStringCreationFailed(err.to_string())
475    }
476}
477
478impl fmt::Display for KernelError {
479    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
480        match self {
481            KernelError::Internal(msg)
482            | KernelError::CStringCreationFailed(msg)
483            | KernelError::InvalidOptions(msg) => write!(f, "{}", msg),
484            _ => write!(f, "Error!"),
485        }
486    }
487}
488
489/// Whether a validated data structure is valid, invalid, or an error was
490/// encountered during processing.
491pub enum ValidationMode {
492    VALID,
493    INVALID,
494    ERROR,
495}
496
497impl From<kernel_ValidationMode> for ValidationMode {
498    fn from(mode: kernel_ValidationMode) -> Self {
499        match mode {
500            kernel_ValidationMode_kernel_VALIDATION_STATE_VALID => Self::VALID,
501            kernel_ValidationMode_kernel_VALIDATION_STATE_INVALID => Self::INVALID,
502            kernel_ValidationMode_kernel_VALIDATION_STATE_ERROR => Self::ERROR,
503            _ => ValidationMode::ERROR, // This should never happen
504        }
505    }
506}
507
508/// A granular reason why a block was invalid.
509pub enum BlockValidationResult {
510    /// initial value. Block has not yet been rejected
511    RESULT_UNSET = 0,
512    /// invalid by consensus rules (excluding any below reasons)
513    CONSENSUS,
514    /// this block was cached as being invalid and we didn't store the reason why
515    CACHED_INVALID,
516    /// invalid proof of work or time too old
517    INVALID_HEADER,
518    /// the block's data didn't match the data committed to by the PoW
519    MUTATED,
520    /// We don't have the previous block the checked one is built on
521    MISSING_PREV,
522    /// A block this one builds on is invalid
523    INVALID_PREV,
524    /// block timestamp was > 2 hours in the future (or our clock is bad)
525    TIME_FUTURE,
526    /// the block header may be on a too-little-work chain
527    HEADER_LOW_WORK,
528}
529
530impl From<kernel_BlockValidationResult> for BlockValidationResult {
531    fn from(res: kernel_BlockValidationResult) -> Self {
532        match res {
533            kernel_BlockValidationResult_kernel_BLOCK_RESULT_UNSET => Self::RESULT_UNSET,
534            kernel_BlockValidationResult_kernel_BLOCK_CONSENSUS => Self::CONSENSUS,
535            kernel_BlockValidationResult_kernel_BLOCK_CACHED_INVALID => Self::CACHED_INVALID,
536            kernel_BlockValidationResult_kernel_BLOCK_INVALID_HEADER => Self::INVALID_HEADER,
537            kernel_BlockValidationResult_kernel_BLOCK_MUTATED => Self::MUTATED,
538            kernel_BlockValidationResult_kernel_BLOCK_MISSING_PREV => Self::MISSING_PREV,
539            kernel_BlockValidationResult_kernel_BLOCK_INVALID_PREV => Self::INVALID_PREV,
540            kernel_BlockValidationResult_kernel_BLOCK_TIME_FUTURE => Self::TIME_FUTURE,
541            kernel_BlockValidationResult_kernel_BLOCK_HEADER_LOW_WORK => Self::HEADER_LOW_WORK,
542            _ => Self::CONSENSUS,
543        }
544    }
545}
546
547/// A single script pubkey
548#[derive(Debug, Clone)]
549pub struct ScriptPubkey {
550    inner: *mut kernel_ScriptPubkey,
551}
552
553unsafe impl Send for ScriptPubkey {}
554unsafe impl Sync for ScriptPubkey {}
555
556impl ScriptPubkey {
557    pub fn get(&self) -> Vec<u8> {
558        let script_pubkey = unsafe { kernel_copy_script_pubkey_data(self.inner) };
559        let res = unsafe {
560            std::slice::from_raw_parts(
561                (*script_pubkey).data,
562                (*script_pubkey).size.try_into().unwrap(),
563            )
564        }
565        .to_vec();
566        unsafe { kernel_byte_array_destroy(script_pubkey) };
567        res
568    }
569}
570
571impl TryFrom<&[u8]> for ScriptPubkey {
572    type Error = KernelError;
573
574    fn try_from(raw_script_pubkey: &[u8]) -> Result<Self, Self::Error> {
575        let inner = unsafe {
576            kernel_script_pubkey_create(raw_script_pubkey.as_ptr(), raw_script_pubkey.len())
577        };
578        if inner.is_null() {
579            return Err(KernelError::Internal(
580                "Failed to decode raw transaction".to_string(),
581            ));
582        }
583        Ok(ScriptPubkey { inner })
584    }
585}
586
587impl Drop for ScriptPubkey {
588    fn drop(&mut self) {
589        unsafe { kernel_script_pubkey_destroy(self.inner) }
590    }
591}
592
593/// A single transaction output.
594///
595/// It can be initialized with a script pubkey and amount, and the user may
596/// retrieve a copy of a script pubkey and its amount.
597#[derive(Debug, Clone)]
598pub struct TxOut {
599    inner: *mut kernel_TransactionOutput,
600}
601
602unsafe impl Send for TxOut {}
603unsafe impl Sync for TxOut {}
604
605impl TxOut {
606    pub fn new(script_pubkey: &ScriptPubkey, amount: i64) -> TxOut {
607        TxOut {
608            inner: unsafe { kernel_transaction_output_create(script_pubkey.inner, amount) },
609        }
610    }
611
612    /// Get the amount associated with this transaction output
613    pub fn get_value(&self) -> i64 {
614        unsafe { kernel_get_transaction_output_amount(self.inner) }
615    }
616
617    /// Get the script pubkey of this output
618    pub fn get_script_pubkey(&self) -> ScriptPubkey {
619        ScriptPubkey {
620            inner: unsafe { kernel_copy_script_pubkey_from_output(self.inner) },
621        }
622    }
623}
624
625impl Drop for TxOut {
626    fn drop(&mut self) {
627        unsafe { kernel_transaction_output_destroy(self.inner) }
628    }
629}
630
631/// A single transaction.
632pub struct Transaction {
633    inner: *mut kernel_Transaction,
634}
635
636unsafe impl Send for Transaction {}
637unsafe impl Sync for Transaction {}
638
639impl TryFrom<&[u8]> for Transaction {
640    type Error = KernelError;
641
642    fn try_from(raw_transaction: &[u8]) -> Result<Self, Self::Error> {
643        let inner =
644            unsafe { kernel_transaction_create(raw_transaction.as_ptr(), raw_transaction.len()) };
645        if inner.is_null() {
646            return Err(KernelError::Internal(
647                "Failed to decode raw transaction.".to_string(),
648            ));
649        }
650        Ok(Transaction { inner })
651    }
652}
653
654impl Drop for Transaction {
655    fn drop(&mut self) {
656        unsafe { kernel_transaction_destroy(self.inner) }
657    }
658}
659
660/// A single unowned block. Can only be used for copying data from it.
661pub struct UnownedBlock {
662    inner: *const kernel_BlockPointer,
663}
664
665impl UnownedBlock {
666    fn new(block: *const kernel_BlockPointer) -> UnownedBlock {
667        UnownedBlock { inner: block }
668    }
669
670    pub fn get_hash(&self) -> BlockHash {
671        let hash = unsafe { kernel_block_pointer_get_hash(self.inner) };
672        let res = BlockHash {
673            hash: unsafe { (&*hash).hash },
674        };
675        unsafe { kernel_block_hash_destroy(hash) };
676        return res;
677    }
678}
679
680impl Into<Vec<u8>> for UnownedBlock {
681    fn into(self) -> Vec<u8> {
682        let raw_block = unsafe { kernel_copy_block_pointer_data(self.inner) };
683        let vec = unsafe {
684            std::slice::from_raw_parts((*raw_block).data, (*raw_block).size.try_into().unwrap())
685        }
686        .to_vec();
687        unsafe { kernel_byte_array_destroy(raw_block) };
688        vec
689    }
690}
691
692/// A single Block
693pub struct Block {
694    inner: *mut kernel_Block,
695}
696
697unsafe impl Send for Block {}
698unsafe impl Sync for Block {}
699
700impl Block {
701    pub fn get_hash(&self) -> BlockHash {
702        let hash = unsafe { kernel_block_get_hash(self.inner) };
703        let res = BlockHash {
704            hash: unsafe { (&*hash).hash },
705        };
706        unsafe { kernel_block_hash_destroy(hash) };
707        return res;
708    }
709}
710
711impl Into<Vec<u8>> for Block {
712    fn into(self) -> Vec<u8> {
713        let raw_block = unsafe { kernel_copy_block_data(self.inner) };
714        let vec = unsafe {
715            std::slice::from_raw_parts((*raw_block).data, (*raw_block).size.try_into().unwrap())
716        }
717        .to_vec();
718        unsafe { kernel_byte_array_destroy(raw_block) };
719        vec
720    }
721}
722
723impl TryFrom<&[u8]> for Block {
724    type Error = KernelError;
725
726    fn try_from(raw_block: &[u8]) -> Result<Self, Self::Error> {
727        let inner = unsafe { kernel_block_create(raw_block.as_ptr(), raw_block.len()) };
728        if inner.is_null() {
729            return Err(KernelError::Internal(
730                "Failed to de-serialize Block.".to_string(),
731            ));
732        }
733        Ok(Block { inner })
734    }
735}
736
737impl Drop for Block {
738    fn drop(&mut self) {
739        unsafe { kernel_block_destroy(self.inner) };
740    }
741}
742
743/// A block index that is tied to a specific [`ChainstateManager`].
744///
745/// Internally the [`ChainstateManager`] keeps an in-memory of the current block
746/// tree once it is loaded. The [`BlockIndex`] points to an entry in this tree.
747/// It is only valid as long as the [`ChainstateManager`] it was retrieved from
748/// remains in scope.
749pub struct BlockIndex {
750    inner: *mut kernel_BlockIndex,
751    marker: PhantomData<ChainstateManager>,
752}
753
754unsafe impl Send for BlockIndex {}
755unsafe impl Sync for BlockIndex {}
756
757/// A type for a Block hash.
758#[derive(Debug, Clone, Hash, Eq, PartialEq)]
759pub struct BlockHash {
760    pub hash: [u8; 32],
761}
762
763impl BlockIndex {
764    /// Move to the previous entry in the block tree. E.g. from height n to
765    /// height n-1.
766    pub fn prev(self) -> Result<BlockIndex, KernelError> {
767        let inner = unsafe { kernel_get_previous_block_index(self.inner) };
768        if inner.is_null() {
769            return Err(KernelError::OutOfBounds);
770        }
771        unsafe { kernel_block_index_destroy(self.inner) };
772        Ok(BlockIndex {
773            inner,
774            marker: self.marker,
775        })
776    }
777
778    /// Get the current height associated with this BlockIndex.
779    pub fn height(&self) -> i32 {
780        unsafe { kernel_block_index_get_height(self.inner) }
781    }
782
783    /// Get the current block hash associated with this BlockIndex.
784    pub fn block_hash(&self) -> BlockHash {
785        let hash = unsafe { kernel_block_index_get_block_hash(self.inner) };
786        let res = BlockHash {
787            hash: unsafe { (&*hash).hash },
788        };
789        unsafe { kernel_block_hash_destroy(hash) };
790        return res;
791    }
792}
793
794impl<'a> Drop for BlockIndex {
795    fn drop(&mut self) {
796        unsafe { kernel_block_index_destroy(self.inner) };
797    }
798}
799
800/// The undo data of a block is used internally during re-orgs. It holds the
801/// previous transaction outputs of a block's transactions. This data may be
802/// useful for building indexes.
803pub struct BlockUndo {
804    inner: *mut kernel_BlockUndo,
805    pub n_tx_undo: usize,
806}
807unsafe impl Send for BlockUndo {}
808unsafe impl Sync for BlockUndo {}
809
810impl BlockUndo {
811    /// Gets the number of previous outputs associated with a transaction in a
812    /// [`Block`] by its index.
813    pub fn get_transaction_undo_size(&self, transaction_index: u64) -> u64 {
814        unsafe { kernel_get_transaction_undo_size(self.inner, transaction_index) }
815    }
816
817    /// Gets the previous output of a transaction by its index.
818    pub fn get_prevout_by_index(
819        &self,
820        transaction_index: u64,
821        prevout_index: u64,
822    ) -> Result<TxOut, KernelError> {
823        let prev_out = unsafe {
824            kernel_get_undo_output_by_index(self.inner, transaction_index, prevout_index)
825        };
826        if prev_out.is_null() {
827            return Err(KernelError::OutOfBounds);
828        }
829        let res = TxOut { inner: prev_out };
830        Ok(res)
831    }
832}
833
834impl Drop for BlockUndo {
835    fn drop(&mut self) {
836        unsafe { kernel_block_undo_destroy(self.inner) };
837    }
838}
839
840/// Holds the configuration options for creating a new [`ChainstateManager`]
841pub struct ChainstateManagerOptions {
842    inner: *mut kernel_ChainstateManagerOptions,
843}
844
845impl ChainstateManagerOptions {
846    /// Create a new option
847    ///
848    /// # Arguments
849    /// * `context` -  The [`ChainstateManager`] for which these options are created has to use the same [`Context`].
850    /// * `data_dir` - The directory into which the [`ChainstateManager`] will write its data.
851    pub fn new(context: &Context, data_dir: &str, blocks_dir: &str) -> Result<Self, KernelError> {
852        let c_data_dir = CString::new(data_dir)?;
853        let c_blocks_dir = CString::new(blocks_dir)?;
854        let inner = unsafe {
855            kernel_chainstate_manager_options_create(
856                context.inner,
857                c_data_dir.as_ptr().cast::<i8>(),
858                c_data_dir.as_bytes().len(),
859                c_blocks_dir.as_ptr().cast::<i8>(),
860                c_blocks_dir.as_bytes().len(),
861            )
862        };
863        if inner.is_null() {
864            return Err(KernelError::Internal(
865                "Failed to create chainstate manager options.".to_string(),
866            ));
867        }
868        Ok(Self { inner })
869    }
870
871    /// Set the number of worker threads used by script validation
872    pub fn set_worker_threads(&self, worker_threads: i32) {
873        unsafe {
874            kernel_chainstate_manager_options_set_worker_threads_num(self.inner, worker_threads);
875        }
876    }
877
878    /// Wipe the block tree or chainstate dbs. When wiping the block tree db the
879    /// chainstate db has to be wiped too. Wiping the databases will triggere a
880    /// rebase once import blocks is called.
881    pub fn set_wipe_db(self, wipe_block_tree: bool, wipe_chainstate: bool) -> Self {
882        unsafe {
883            kernel_chainstate_manager_options_set_wipe_dbs(
884                self.inner,
885                wipe_block_tree,
886                wipe_chainstate,
887            );
888        }
889        self
890    }
891
892    /// Run the block tree db in-memory only. No database files will be written to disk.
893    pub fn set_block_tree_db_in_memory(self, block_tree_db_in_memory: bool) -> Self {
894        unsafe {
895            kernel_chainstate_manager_options_set_block_tree_db_in_memory(
896                self.inner,
897                block_tree_db_in_memory,
898            );
899        }
900        self
901    }
902
903    /// Run the chainstate db in-memory only. No database files will be written to disk.
904    pub fn set_chainstate_db_in_memory(self, chainstate_db_in_memory: bool) -> Self {
905        unsafe {
906            kernel_chainstate_manager_options_set_chainstate_db_in_memory(
907                self.inner,
908                chainstate_db_in_memory,
909            );
910        }
911        self
912    }
913}
914
915impl Drop for ChainstateManagerOptions {
916    fn drop(&mut self) {
917        unsafe {
918            kernel_chainstate_manager_options_destroy(self.inner);
919        }
920    }
921}
922
923/// The chainstate manager is the central object for doing validation tasks as
924/// well as retrieving data from the chain. Internally it is a complex data
925/// structure with diverse functionality.
926///
927/// The chainstate manager is only valid for as long as the [`Context`] with which it
928/// was created remains in memory.
929///
930/// Its functionality will be more and more exposed in the future.
931pub struct ChainstateManager {
932    inner: *mut kernel_ChainstateManager,
933    context: Arc<Context>,
934}
935
936unsafe impl Send for ChainstateManager {}
937unsafe impl Sync for ChainstateManager {}
938
939impl<'a> ChainstateManager {
940    pub fn new(
941        chainman_opts: ChainstateManagerOptions,
942        context: Arc<Context>,
943    ) -> Result<Self, KernelError> {
944        let inner = unsafe { kernel_chainstate_manager_create(context.inner, chainman_opts.inner) };
945        if inner.is_null() {
946            return Err(KernelError::Internal(
947                "Failed to create chainstate manager.".to_string(),
948            ));
949        }
950        Ok(Self { inner, context })
951    }
952
953    /// Process and validate the passed in block with the [`ChainstateManager`]
954    /// If processing failed, some information can be retrieved through the status
955    /// enumeration. More detailed validation information in case of a failure can
956    /// also be retrieved through a registered validation interface. If the block
957    /// fails to validate the `block_checked` callback's ['BlockValidationState'] will
958    /// contain details.
959    pub fn process_block(&self, block: &Block) -> (bool /* accepted */, bool /* duplicate */) {
960        let mut new_block = true.into();
961        let accepted = unsafe {
962            kernel_chainstate_manager_process_block(
963                self.context.inner,
964                self.inner,
965                block.inner,
966                &mut new_block,
967            )
968        };
969        (accepted, new_block)
970    }
971
972    /// May be called after load_chainstate to initialize the
973    /// [`ChainstateManager`]. Triggers the start of a reindex if the option was
974    /// previously set for the chainstate and block manager. Can also import an
975    /// array of existing block files selected by the user.
976    pub fn import_blocks(&self) -> Result<(), KernelError> {
977        if !unsafe {
978            kernel_import_blocks(
979                self.context.inner,
980                self.inner,
981                std::ptr::null_mut(),
982                std::ptr::null_mut(),
983                0,
984            )
985        } {
986            return Err(KernelError::Internal(
987                "Failed to import blocks.".to_string(),
988            ));
989        }
990        Ok(())
991    }
992
993    /// Get the block index entry of the current chain tip. Once returned,
994    /// there is no guarantee that it remains in the active chain.
995    pub fn get_block_index_tip(&self) -> BlockIndex {
996        BlockIndex {
997            inner: unsafe { kernel_get_block_index_from_tip(self.context.inner, self.inner) },
998            marker: PhantomData,
999        }
1000    }
1001
1002    /// Get the block index entry of the genesis block.
1003    pub fn get_block_index_genesis(&self) -> BlockIndex {
1004        BlockIndex {
1005            inner: unsafe { kernel_get_block_index_from_genesis(self.context.inner, self.inner) },
1006            marker: PhantomData,
1007        }
1008    }
1009
1010    /// Retrieve a block index by its height in the currently active chain.
1011    /// Once retrieved there is no guarantee that it remains in the active chain.
1012    pub fn get_block_index_by_height(&self, block_height: i32) -> Result<BlockIndex, KernelError> {
1013        let inner = unsafe {
1014            kernel_get_block_index_from_height(self.context.inner, self.inner, block_height)
1015        };
1016        if inner.is_null() {
1017            return Err(KernelError::OutOfBounds);
1018        }
1019        Ok(BlockIndex {
1020            inner,
1021            marker: PhantomData,
1022        })
1023    }
1024
1025    /// Get a block index entry by its hash.
1026    pub fn get_block_index_by_hash(&self, hash: BlockHash) -> Result<BlockIndex, KernelError> {
1027        let mut block_hash = kernel_BlockHash { hash: hash.hash };
1028        let inner = unsafe {
1029            kernel_get_block_index_from_hash(self.context.inner, self.inner, &mut block_hash)
1030        };
1031        if inner.is_null() {
1032            return Err(KernelError::Internal(
1033                "Block index for the given block hash not found.".to_string(),
1034            ));
1035        }
1036        Ok(BlockIndex {
1037            inner,
1038            marker: PhantomData,
1039        })
1040    }
1041
1042    /// Get the next block index entry in the chain. If this is the tip, or
1043    /// otherwise a leaf in the block tree, return an error.
1044    pub fn get_next_block_index(&self, block_index: BlockIndex) -> Result<BlockIndex, KernelError> {
1045        let inner = unsafe {
1046            kernel_get_next_block_index(self.context.inner, self.inner, block_index.inner)
1047        };
1048        if inner.is_null() {
1049            return Err(KernelError::OutOfBounds);
1050        }
1051        Ok(BlockIndex {
1052            inner,
1053            marker: PhantomData,
1054        })
1055    }
1056
1057    /// Read a block from disk by its block index.
1058    pub fn read_block_data(&self, block_index: &BlockIndex) -> Result<Block, KernelError> {
1059        let inner = unsafe {
1060            kernel_read_block_from_disk(self.context.inner, self.inner, block_index.inner)
1061        };
1062        if inner.is_null() {
1063            return Err(KernelError::Internal("Failed to read block.".to_string()));
1064        }
1065        Ok(Block { inner })
1066    }
1067
1068    /// Read a block's undo data from disk by its block index.
1069    pub fn read_undo_data(&self, block_index: &BlockIndex) -> Result<BlockUndo, KernelError> {
1070        let inner = unsafe {
1071            kernel_read_block_undo_from_disk(self.context.inner, self.inner, block_index.inner)
1072        };
1073        if inner.is_null() {
1074            return Err(KernelError::Internal(
1075                "Failed to read undo data.".to_string(),
1076            ));
1077        }
1078        let n_tx_undo = unsafe { kernel_block_undo_size(inner) }.try_into().unwrap();
1079        Ok(BlockUndo { inner, n_tx_undo })
1080    }
1081}
1082
1083impl Drop for ChainstateManager {
1084    fn drop(&mut self) {
1085        unsafe {
1086            kernel_chainstate_manager_destroy(self.inner, self.context.inner);
1087        }
1088    }
1089}
1090
1091/// A function for handling log messages produced by the kernel library.
1092pub trait Log {
1093    fn log(&self, message: &str);
1094}
1095
1096unsafe extern "C" fn log_callback<T: Log + 'static>(
1097    user_data: *mut c_void,
1098    message: *const c_char,
1099    message_len: usize,
1100) {
1101    let message = unsafe { cast_string(message, message_len) };
1102    let log = user_data as *mut T;
1103    (*log).log(&message);
1104}
1105
1106/// The logger object logs kernel log messages into a user-defined log function.
1107/// Messages logged by the kernel before this object is created are buffered in
1108/// a 1MB buffer. The kernel library internally uses a global logging instance.
1109pub struct Logger<T> {
1110    log: T,
1111    inner: *mut kernel_LoggingConnection,
1112}
1113
1114impl<T> Drop for Logger<T> {
1115    fn drop(&mut self) {
1116        unsafe {
1117            kernel_logging_connection_destroy(self.inner);
1118        }
1119    }
1120}
1121
1122/// Permanently disable logging and stop buffering.
1123pub fn disable_logging() {
1124    unsafe {
1125        kernel_disable_logging();
1126    }
1127}
1128
1129impl<T: Log + 'static> Logger<T> {
1130    /// Create a new Logger with the specified callback.
1131    pub fn new(mut log: T) -> Result<Logger<T>, KernelError> {
1132        let options = kernel_LoggingOptions {
1133            log_timestamps: true,
1134            log_time_micros: false,
1135            log_threadnames: false,
1136            log_sourcelocations: false,
1137            always_print_category_levels: false,
1138        };
1139
1140        let inner = unsafe {
1141            kernel_logging_connection_create(
1142                Some(log_callback::<T>),
1143                &mut log as *mut T as *mut c_void,
1144                options,
1145            )
1146        };
1147
1148        if inner.is_null() {
1149            return Err(KernelError::Internal(
1150                "Failed to create new logging connection.".to_string(),
1151            ));
1152        }
1153
1154        Ok(Logger { log, inner })
1155    }
1156
1157    /// Manually log something through the user-specified callback.
1158    pub fn log(&self, message: &str) {
1159        self.log.log(message);
1160    }
1161}