use std::{
fmt,
str::{self, FromStr},
};
use bitcoin::{self, Script};
use super::{checksum::verify_checksum, Bare, Pkh, Sh, Wpkh, Wsh};
use {expression, DescriptorTrait, Error, MiniscriptKey, Satisfier, ToPublicKey};
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum PreTaprootDescriptor<Pk: MiniscriptKey> {
Bare(Bare<Pk>),
Pkh(Pkh<Pk>),
Wpkh(Wpkh<Pk>),
Sh(Sh<Pk>),
Wsh(Wsh<Pk>),
}
impl<Pk: MiniscriptKey> DescriptorTrait<Pk> for PreTaprootDescriptor<Pk> {
fn sanity_check(&self) -> Result<(), Error> {
match *self {
PreTaprootDescriptor::Bare(ref bare) => bare.sanity_check(),
PreTaprootDescriptor::Pkh(ref pkh) => pkh.sanity_check(),
PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.sanity_check(),
PreTaprootDescriptor::Wsh(ref wsh) => wsh.sanity_check(),
PreTaprootDescriptor::Sh(ref sh) => sh.sanity_check(),
}
}
fn address(&self, network: bitcoin::Network) -> Result<bitcoin::Address, Error>
where
Pk: ToPublicKey,
{
match *self {
PreTaprootDescriptor::Bare(ref bare) => bare.address(network),
PreTaprootDescriptor::Pkh(ref pkh) => pkh.address(network),
PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.address(network),
PreTaprootDescriptor::Wsh(ref wsh) => wsh.address(network),
PreTaprootDescriptor::Sh(ref sh) => sh.address(network),
}
}
fn script_pubkey(&self) -> Script
where
Pk: ToPublicKey,
{
match *self {
PreTaprootDescriptor::Bare(ref bare) => bare.script_pubkey(),
PreTaprootDescriptor::Pkh(ref pkh) => pkh.script_pubkey(),
PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.script_pubkey(),
PreTaprootDescriptor::Wsh(ref wsh) => wsh.script_pubkey(),
PreTaprootDescriptor::Sh(ref sh) => sh.script_pubkey(),
}
}
fn unsigned_script_sig(&self) -> Script
where
Pk: ToPublicKey,
{
match *self {
PreTaprootDescriptor::Bare(ref bare) => bare.unsigned_script_sig(),
PreTaprootDescriptor::Pkh(ref pkh) => pkh.unsigned_script_sig(),
PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.unsigned_script_sig(),
PreTaprootDescriptor::Wsh(ref wsh) => wsh.unsigned_script_sig(),
PreTaprootDescriptor::Sh(ref sh) => sh.unsigned_script_sig(),
}
}
fn explicit_script(&self) -> Result<Script, Error>
where
Pk: ToPublicKey,
{
match *self {
PreTaprootDescriptor::Bare(ref bare) => bare.explicit_script(),
PreTaprootDescriptor::Pkh(ref pkh) => pkh.explicit_script(),
PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.explicit_script(),
PreTaprootDescriptor::Wsh(ref wsh) => wsh.explicit_script(),
PreTaprootDescriptor::Sh(ref sh) => sh.explicit_script(),
}
}
fn get_satisfaction<S>(&self, satisfier: S) -> Result<(Vec<Vec<u8>>, Script), Error>
where
Pk: ToPublicKey,
S: Satisfier<Pk>,
{
match *self {
PreTaprootDescriptor::Bare(ref bare) => bare.get_satisfaction(satisfier),
PreTaprootDescriptor::Pkh(ref pkh) => pkh.get_satisfaction(satisfier),
PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.get_satisfaction(satisfier),
PreTaprootDescriptor::Wsh(ref wsh) => wsh.get_satisfaction(satisfier),
PreTaprootDescriptor::Sh(ref sh) => sh.get_satisfaction(satisfier),
}
}
fn get_satisfaction_mall<S>(&self, satisfier: S) -> Result<(Vec<Vec<u8>>, Script), Error>
where
Pk: ToPublicKey,
S: Satisfier<Pk>,
{
match *self {
PreTaprootDescriptor::Bare(ref bare) => bare.get_satisfaction_mall(satisfier),
PreTaprootDescriptor::Pkh(ref pkh) => pkh.get_satisfaction_mall(satisfier),
PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.get_satisfaction_mall(satisfier),
PreTaprootDescriptor::Wsh(ref wsh) => wsh.get_satisfaction_mall(satisfier),
PreTaprootDescriptor::Sh(ref sh) => sh.get_satisfaction_mall(satisfier),
}
}
fn max_satisfaction_weight(&self) -> Result<usize, Error> {
match *self {
PreTaprootDescriptor::Bare(ref bare) => bare.max_satisfaction_weight(),
PreTaprootDescriptor::Pkh(ref pkh) => pkh.max_satisfaction_weight(),
PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.max_satisfaction_weight(),
PreTaprootDescriptor::Wsh(ref wsh) => wsh.max_satisfaction_weight(),
PreTaprootDescriptor::Sh(ref sh) => sh.max_satisfaction_weight(),
}
}
fn script_code(&self) -> Result<Script, Error>
where
Pk: ToPublicKey,
{
match *self {
PreTaprootDescriptor::Bare(ref bare) => bare.script_code(),
PreTaprootDescriptor::Pkh(ref pkh) => pkh.script_code(),
PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.script_code(),
PreTaprootDescriptor::Wsh(ref wsh) => wsh.script_code(),
PreTaprootDescriptor::Sh(ref sh) => sh.script_code(),
}
}
}
impl<Pk> expression::FromTree for PreTaprootDescriptor<Pk>
where
Pk: MiniscriptKey + str::FromStr,
Pk::Hash: str::FromStr,
<Pk as FromStr>::Err: ToString,
<<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString,
{
fn from_tree(top: &expression::Tree) -> Result<PreTaprootDescriptor<Pk>, Error> {
Ok(match (top.name, top.args.len() as u32) {
("pkh", 1) => PreTaprootDescriptor::Pkh(Pkh::from_tree(top)?),
("wpkh", 1) => PreTaprootDescriptor::Wpkh(Wpkh::from_tree(top)?),
("sh", 1) => PreTaprootDescriptor::Sh(Sh::from_tree(top)?),
("wsh", 1) => PreTaprootDescriptor::Wsh(Wsh::from_tree(top)?),
_ => PreTaprootDescriptor::Bare(Bare::from_tree(top)?),
})
}
}
impl<Pk> FromStr for PreTaprootDescriptor<Pk>
where
Pk: MiniscriptKey + str::FromStr,
Pk::Hash: str::FromStr,
<Pk as FromStr>::Err: ToString,
<<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString,
{
type Err = Error;
fn from_str(s: &str) -> Result<PreTaprootDescriptor<Pk>, Error> {
let desc_str = verify_checksum(s)?;
let top = expression::Tree::from_str(desc_str)?;
expression::FromTree::from_tree(&top)
}
}
impl<Pk: MiniscriptKey> fmt::Debug for PreTaprootDescriptor<Pk> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
PreTaprootDescriptor::Bare(ref sub) => write!(f, "{:?}", sub),
PreTaprootDescriptor::Pkh(ref pkh) => write!(f, "{:?}", pkh),
PreTaprootDescriptor::Wpkh(ref wpkh) => write!(f, "{:?}", wpkh),
PreTaprootDescriptor::Sh(ref sub) => write!(f, "{:?}", sub),
PreTaprootDescriptor::Wsh(ref sub) => write!(f, "{:?}", sub),
}
}
}
impl<Pk: MiniscriptKey> fmt::Display for PreTaprootDescriptor<Pk> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
PreTaprootDescriptor::Bare(ref sub) => write!(f, "{}", sub),
PreTaprootDescriptor::Pkh(ref pkh) => write!(f, "{}", pkh),
PreTaprootDescriptor::Wpkh(ref wpkh) => write!(f, "{}", wpkh),
PreTaprootDescriptor::Sh(ref sub) => write!(f, "{}", sub),
PreTaprootDescriptor::Wsh(ref sub) => write!(f, "{}", sub),
}
}
}
serde_string_impl_pk!(PreTaprootDescriptor, "a pre-taproot script descriptor");
pub(crate) mod traits {
use bitcoin::Script;
use {
descriptor::{Pkh, Sh, Wpkh, Wsh},
DescriptorTrait, MiniscriptKey, ToPublicKey,
};
use super::PreTaprootDescriptor;
pub trait PreTaprootDescriptorTrait<Pk: MiniscriptKey>: DescriptorTrait<Pk> {
fn explicit_script(&self) -> Script
where
Pk: ToPublicKey,
{
<Self as DescriptorTrait<Pk>>::explicit_script(&self)
.expect("Pre taproot descriptor have explicit script")
}
fn script_code(&self) -> Script
where
Pk: ToPublicKey,
{
<Self as DescriptorTrait<Pk>>::script_code(&self)
.expect("Pre taproot descriptor have non-failing script code")
}
}
impl<Pk: MiniscriptKey> PreTaprootDescriptorTrait<Pk> for Pkh<Pk> {}
impl<Pk: MiniscriptKey> PreTaprootDescriptorTrait<Pk> for Sh<Pk> {}
impl<Pk: MiniscriptKey> PreTaprootDescriptorTrait<Pk> for Wpkh<Pk> {}
impl<Pk: MiniscriptKey> PreTaprootDescriptorTrait<Pk> for Wsh<Pk> {}
impl<Pk: MiniscriptKey> PreTaprootDescriptorTrait<Pk> for PreTaprootDescriptor<Pk> {}
}