use alloc::boxed::Box;
use chain::{ChainPosition, ConfirmationBlockTime};
use core::convert::AsRef;
use core::fmt;
use bitcoin::transaction::{OutPoint, Sequence, TxOut};
use bitcoin::{psbt, Weight};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub enum KeychainKind {
External = 0,
Internal = 1,
}
impl KeychainKind {
pub fn as_byte(&self) -> u8 {
match self {
KeychainKind::External => b'e',
KeychainKind::Internal => b'i',
}
}
}
impl fmt::Display for KeychainKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
KeychainKind::External => write!(f, "External"),
KeychainKind::Internal => write!(f, "Internal"),
}
}
}
impl AsRef<[u8]> for KeychainKind {
fn as_ref(&self) -> &[u8] {
match self {
KeychainKind::External => b"e",
KeychainKind::Internal => b"i",
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct LocalOutput {
pub outpoint: OutPoint,
pub txout: TxOut,
pub keychain: KeychainKind,
pub is_spent: bool,
pub derivation_index: u32,
pub chain_position: ChainPosition<ConfirmationBlockTime>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct WeightedUtxo {
pub satisfaction_weight: Weight,
pub utxo: Utxo,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Utxo {
Local(LocalOutput),
Foreign {
outpoint: OutPoint,
sequence: Sequence,
psbt_input: Box<psbt::Input>,
},
}
impl Utxo {
pub fn outpoint(&self) -> OutPoint {
match &self {
Utxo::Local(local) => local.outpoint,
Utxo::Foreign { outpoint, .. } => *outpoint,
}
}
pub fn txout(&self) -> &TxOut {
match &self {
Utxo::Local(local) => &local.txout,
Utxo::Foreign {
outpoint,
psbt_input,
..
} => {
if let Some(prev_tx) = &psbt_input.non_witness_utxo {
return &prev_tx.output[outpoint.vout as usize];
}
if let Some(txout) = &psbt_input.witness_utxo {
return txout;
}
unreachable!("Foreign UTXOs will always have one of these set")
}
}
}
pub fn sequence(&self) -> Option<Sequence> {
match self {
Utxo::Local(_) => None,
Utxo::Foreign { sequence, .. } => Some(*sequence),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct IndexOutOfBoundsError {
pub index: usize,
pub len: usize,
}
impl IndexOutOfBoundsError {
pub fn new(index: usize, len: usize) -> Self {
Self { index, len }
}
}
impl fmt::Display for IndexOutOfBoundsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Index out of bounds: index {} is greater than or equal to length {}",
self.index, self.len
)
}
}
impl core::error::Error for IndexOutOfBoundsError {}