use amplify::Wrapper;
use std::convert::TryFrom;
use super::Category;
use crate::script::{PubkeyScript, WitnessVersion};
#[derive(
Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display, Error,
)]
#[display(doc_comments)]
pub enum DeductionError {
IncompleteInformation,
UnsupportedWitnessVersion(WitnessVersion),
}
pub trait Deduce {
fn deduce(
pubkey_script: &PubkeyScript,
has_witness: Option<bool>,
) -> Result<Category, DeductionError>;
}
impl Deduce for Category {
fn deduce(
pubkey_script: &PubkeyScript,
has_witness: Option<bool>,
) -> Result<Category, DeductionError> {
match pubkey_script.as_inner() {
p if p.is_v0_p2wpkh() || p.is_v0_p2wsh() => Ok(Category::SegWit),
p if p.is_witness_program() => {
const ERR: &'static str =
"bitcoin::Script::is_witness_program is broken";
match WitnessVersion::try_from(
p.instructions_minimal().next().expect(ERR).expect(ERR),
)
.expect(ERR)
{
WitnessVersion::V0 => unreachable!(),
WitnessVersion::V1 => Ok(Category::Taproot),
ver => Err(DeductionError::UnsupportedWitnessVersion(ver)),
}
}
p if p.is_p2pkh() => Ok(Category::Hashed),
p if p.is_p2sh() => match has_witness {
None => Err(DeductionError::IncompleteInformation),
Some(true) => Ok(Category::Nested),
Some(false) => Ok(Category::Hashed),
},
_ => Ok(Category::Bare),
}
}
}