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