use core::convert::TryFrom;
use core::fmt;
use bitcoin::{Address, Network, ScriptBuf, Weight};
use super::checksum::verify_checksum;
use super::SortedMultiVec;
use crate::descriptor::{write_descriptor, DefiniteDescriptorKey};
use crate::expression::{self, FromTree};
use crate::miniscript::context::{ScriptContext, ScriptContextError};
use crate::miniscript::satisfy::{Placeholder, Satisfaction, Witness};
use crate::plan::AssetProvider;
use crate::policy::{semantic, Liftable};
use crate::prelude::*;
use crate::util::varint_len;
use crate::{
Error, ForEachKey, FromStrKey, Miniscript, MiniscriptKey, Satisfier, Segwitv0, ToPublicKey,
TranslateErr, TranslatePk, Translator,
};
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct Wsh<Pk: MiniscriptKey> {
inner: WshInner<Pk>,
}
impl<Pk: MiniscriptKey> Wsh<Pk> {
pub fn into_inner(self) -> WshInner<Pk> { self.inner }
pub fn as_inner(&self) -> &WshInner<Pk> { &self.inner }
pub fn new(ms: Miniscript<Pk, Segwitv0>) -> Result<Self, Error> {
Segwitv0::top_level_checks(&ms)?;
Ok(Self { inner: WshInner::Ms(ms) })
}
pub fn new_sortedmulti(k: usize, pks: Vec<Pk>) -> Result<Self, Error> {
Ok(Self { inner: WshInner::SortedMulti(SortedMultiVec::new(k, pks)?) })
}
#[deprecated(since = "8.0.0", note = "use format!(\"{:#}\") instead")]
pub fn to_string_no_checksum(&self) -> String { format!("{:#}", self) }
pub fn sanity_check(&self) -> Result<(), Error> {
match self.inner {
WshInner::SortedMulti(ref smv) => smv.sanity_check()?,
WshInner::Ms(ref ms) => ms.sanity_check()?,
}
Ok(())
}
pub fn max_weight_to_satisfy(&self) -> Result<Weight, Error> {
let (redeem_script_size, max_sat_elems, max_sat_size) = match self.inner {
WshInner::SortedMulti(ref smv) => (
smv.script_size(),
smv.max_satisfaction_witness_elements(),
smv.max_satisfaction_size(),
),
WshInner::Ms(ref ms) => (
ms.script_size(),
ms.max_satisfaction_witness_elements()?,
ms.max_satisfaction_size()?,
),
};
let stack_varint_diff = varint_len(max_sat_elems) - varint_len(0);
Ok(Weight::from_wu(
(stack_varint_diff + varint_len(redeem_script_size) + redeem_script_size + max_sat_size)
as u64,
))
}
#[deprecated(
since = "10.0.0",
note = "Use max_weight_to_satisfy instead. The method to count bytes was redesigned and the results will differ from max_weight_to_satisfy. For more details check rust-bitcoin/rust-miniscript#476."
)]
pub fn max_satisfaction_weight(&self) -> Result<usize, Error> {
let (script_size, max_sat_elems, max_sat_size) = match self.inner {
WshInner::SortedMulti(ref smv) => (
smv.script_size(),
smv.max_satisfaction_witness_elements(),
smv.max_satisfaction_size(),
),
WshInner::Ms(ref ms) => (
ms.script_size(),
ms.max_satisfaction_witness_elements()?,
ms.max_satisfaction_size()?,
),
};
Ok(4 + varint_len(script_size) +
script_size +
varint_len(max_sat_elems) +
max_sat_size)
}
}
impl<Pk: MiniscriptKey + ToPublicKey> Wsh<Pk> {
pub fn script_pubkey(&self) -> ScriptBuf { self.inner_script().to_p2wsh() }
pub fn address(&self, network: Network) -> Address {
match self.inner {
WshInner::SortedMulti(ref smv) => Address::p2wsh(&smv.encode(), network),
WshInner::Ms(ref ms) => Address::p2wsh(&ms.encode(), network),
}
}
pub fn inner_script(&self) -> ScriptBuf {
match self.inner {
WshInner::SortedMulti(ref smv) => smv.encode(),
WshInner::Ms(ref ms) => ms.encode(),
}
}
pub fn ecdsa_sighash_script_code(&self) -> ScriptBuf { self.inner_script() }
pub fn get_satisfaction<S>(&self, satisfier: S) -> Result<(Vec<Vec<u8>>, ScriptBuf), Error>
where
S: Satisfier<Pk>,
{
let mut witness = match self.inner {
WshInner::SortedMulti(ref smv) => smv.satisfy(satisfier)?,
WshInner::Ms(ref ms) => ms.satisfy(satisfier)?,
};
let witness_script = self.inner_script();
witness.push(witness_script.into_bytes());
let script_sig = ScriptBuf::new();
Ok((witness, script_sig))
}
pub fn get_satisfaction_mall<S>(&self, satisfier: S) -> Result<(Vec<Vec<u8>>, ScriptBuf), Error>
where
S: Satisfier<Pk>,
{
let mut witness = match self.inner {
WshInner::SortedMulti(ref smv) => smv.satisfy(satisfier)?,
WshInner::Ms(ref ms) => ms.satisfy_malleable(satisfier)?,
};
witness.push(self.inner_script().into_bytes());
let script_sig = ScriptBuf::new();
Ok((witness, script_sig))
}
}
impl Wsh<DefiniteDescriptorKey> {
pub fn plan_satisfaction<P>(
&self,
provider: &P,
) -> Satisfaction<Placeholder<DefiniteDescriptorKey>>
where
P: AssetProvider<DefiniteDescriptorKey>,
{
match &self.inner {
WshInner::SortedMulti(sm) => sm.build_template(provider),
WshInner::Ms(ms) => ms.build_template(provider),
}
}
pub fn plan_satisfaction_mall<P>(
&self,
provider: &P,
) -> Satisfaction<Placeholder<DefiniteDescriptorKey>>
where
P: AssetProvider<DefiniteDescriptorKey>,
{
match &self.inner {
WshInner::SortedMulti(sm) => sm.build_template(provider),
WshInner::Ms(ms) => ms.build_template_mall(provider),
}
}
}
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub enum WshInner<Pk: MiniscriptKey> {
SortedMulti(SortedMultiVec<Pk, Segwitv0>),
Ms(Miniscript<Pk, Segwitv0>),
}
impl<Pk: MiniscriptKey> Liftable<Pk> for Wsh<Pk> {
fn lift(&self) -> Result<semantic::Policy<Pk>, Error> {
match self.inner {
WshInner::SortedMulti(ref smv) => smv.lift(),
WshInner::Ms(ref ms) => ms.lift(),
}
}
}
impl<Pk: FromStrKey> crate::expression::FromTree for Wsh<Pk> {
fn from_tree(top: &expression::Tree) -> Result<Self, Error> {
if top.name == "wsh" && top.args.len() == 1 {
let top = &top.args[0];
if top.name == "sortedmulti" {
return Ok(Wsh { inner: WshInner::SortedMulti(SortedMultiVec::from_tree(top)?) });
}
let sub = Miniscript::from_tree(top)?;
Segwitv0::top_level_checks(&sub)?;
Ok(Wsh { inner: WshInner::Ms(sub) })
} else {
Err(Error::Unexpected(format!(
"{}({} args) while parsing wsh descriptor",
top.name,
top.args.len(),
)))
}
}
}
impl<Pk: MiniscriptKey> fmt::Debug for Wsh<Pk> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.inner {
WshInner::SortedMulti(ref smv) => write!(f, "wsh({:?})", smv),
WshInner::Ms(ref ms) => write!(f, "wsh({:?})", ms),
}
}
}
impl<Pk: MiniscriptKey> fmt::Display for Wsh<Pk> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.inner {
WshInner::SortedMulti(ref smv) => write_descriptor!(f, "wsh({})", smv),
WshInner::Ms(ref ms) => write_descriptor!(f, "wsh({})", ms),
}
}
}
impl<Pk: FromStrKey> core::str::FromStr for Wsh<Pk> {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let desc_str = verify_checksum(s)?;
let top = expression::Tree::from_str(desc_str)?;
Wsh::<Pk>::from_tree(&top)
}
}
impl<Pk: MiniscriptKey> ForEachKey<Pk> for Wsh<Pk> {
fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, pred: F) -> bool {
match self.inner {
WshInner::SortedMulti(ref smv) => smv.for_each_key(pred),
WshInner::Ms(ref ms) => ms.for_each_key(pred),
}
}
}
impl<P, Q> TranslatePk<P, Q> for Wsh<P>
where
P: MiniscriptKey,
Q: MiniscriptKey,
{
type Output = Wsh<Q>;
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, TranslateErr<E>>
where
T: Translator<P, Q, E>,
{
let inner = match self.inner {
WshInner::SortedMulti(ref smv) => WshInner::SortedMulti(smv.translate_pk(t)?),
WshInner::Ms(ref ms) => WshInner::Ms(ms.translate_pk(t)?),
};
Ok(Wsh { inner })
}
}
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct Wpkh<Pk: MiniscriptKey> {
pk: Pk,
}
impl<Pk: MiniscriptKey> Wpkh<Pk> {
pub fn new(pk: Pk) -> Result<Self, ScriptContextError> {
match Segwitv0::check_pk(&pk) {
Ok(_) => Ok(Wpkh { pk }),
Err(e) => Err(e),
}
}
pub fn into_inner(self) -> Pk { self.pk }
pub fn as_inner(&self) -> &Pk { &self.pk }
#[deprecated(since = "8.0.0", note = "use format!(\"{:#}\") instead")]
pub fn to_string_no_checksum(&self) -> String { format!("{:#}", self) }
pub fn sanity_check(&self) -> Result<(), Error> {
if self.pk.is_uncompressed() {
Err(Error::ContextError(ScriptContextError::CompressedOnly(self.pk.to_string())))
} else {
Ok(())
}
}
pub fn max_weight_to_satisfy(&self) -> Weight {
let stack_items_size = 73 + Segwitv0::pk_len(&self.pk);
let stack_varint_diff = varint_len(2) - varint_len(0);
Weight::from_wu((stack_varint_diff + stack_items_size) as u64)
}
#[deprecated(
since = "10.0.0",
note = "Use max_weight_to_satisfy instead. The method to count bytes was redesigned and the results will differ from max_weight_to_satisfy. For more details check rust-bitcoin/rust-miniscript#476."
)]
pub fn max_satisfaction_weight(&self) -> usize { 4 + 1 + 73 + Segwitv0::pk_len(&self.pk) }
}
impl<Pk: MiniscriptKey + ToPublicKey> Wpkh<Pk> {
pub fn script_pubkey(&self) -> ScriptBuf {
let pk = self.pk.to_public_key();
let compressed = bitcoin::key::CompressedPublicKey::try_from(pk)
.expect("wpkh descriptors have compressed keys");
let addr = Address::p2wpkh(&compressed, Network::Bitcoin);
addr.script_pubkey()
}
pub fn address(&self, network: Network) -> Address {
let pk = self.pk.to_public_key();
let compressed = bitcoin::key::CompressedPublicKey::try_from(pk)
.expect("Rust Miniscript types don't allow uncompressed pks in segwit descriptors");
Address::p2wpkh(&compressed, network)
}
pub fn inner_script(&self) -> ScriptBuf { self.script_pubkey() }
pub fn ecdsa_sighash_script_code(&self) -> ScriptBuf {
let addr = Address::p2pkh(self.pk.to_public_key(), Network::Bitcoin);
addr.script_pubkey()
}
pub fn get_satisfaction<S>(&self, satisfier: S) -> Result<(Vec<Vec<u8>>, ScriptBuf), Error>
where
S: Satisfier<Pk>,
{
if let Some(sig) = satisfier.lookup_ecdsa_sig(&self.pk) {
let sig_vec = sig.to_vec();
let script_sig = ScriptBuf::new();
let witness = vec![sig_vec, self.pk.to_public_key().to_bytes()];
Ok((witness, script_sig))
} else {
Err(Error::MissingSig(self.pk.to_public_key()))
}
}
pub fn get_satisfaction_mall<S>(&self, satisfier: S) -> Result<(Vec<Vec<u8>>, ScriptBuf), Error>
where
S: Satisfier<Pk>,
{
self.get_satisfaction(satisfier)
}
}
impl Wpkh<DefiniteDescriptorKey> {
pub fn plan_satisfaction<P>(
&self,
provider: &P,
) -> Satisfaction<Placeholder<DefiniteDescriptorKey>>
where
P: AssetProvider<DefiniteDescriptorKey>,
{
let stack = if provider.provider_lookup_ecdsa_sig(&self.pk) {
let stack = vec![
Placeholder::EcdsaSigPk(self.pk.clone()),
Placeholder::Pubkey(self.pk.clone(), Segwitv0::pk_len(&self.pk)),
];
Witness::Stack(stack)
} else {
Witness::Unavailable
};
Satisfaction { stack, has_sig: true, relative_timelock: None, absolute_timelock: None }
}
pub fn plan_satisfaction_mall<P>(
&self,
provider: &P,
) -> Satisfaction<Placeholder<DefiniteDescriptorKey>>
where
P: AssetProvider<DefiniteDescriptorKey>,
{
self.plan_satisfaction(provider)
}
}
impl<Pk: MiniscriptKey> fmt::Debug for Wpkh<Pk> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "wpkh({:?})", self.pk) }
}
impl<Pk: MiniscriptKey> fmt::Display for Wpkh<Pk> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write_descriptor!(f, "wpkh({})", self.pk)
}
}
impl<Pk: MiniscriptKey> Liftable<Pk> for Wpkh<Pk> {
fn lift(&self) -> Result<semantic::Policy<Pk>, Error> {
Ok(semantic::Policy::Key(self.pk.clone()))
}
}
impl<Pk: FromStrKey> crate::expression::FromTree for Wpkh<Pk> {
fn from_tree(top: &expression::Tree) -> Result<Self, Error> {
if top.name == "wpkh" && top.args.len() == 1 {
Ok(Wpkh::new(expression::terminal(&top.args[0], |pk| Pk::from_str(pk))?)?)
} else {
Err(Error::Unexpected(format!(
"{}({} args) while parsing wpkh descriptor",
top.name,
top.args.len(),
)))
}
}
}
impl<Pk: FromStrKey> core::str::FromStr for Wpkh<Pk> {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let desc_str = verify_checksum(s)?;
let top = expression::Tree::from_str(desc_str)?;
Self::from_tree(&top)
}
}
impl<Pk: MiniscriptKey> ForEachKey<Pk> for Wpkh<Pk> {
fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool { pred(&self.pk) }
}
impl<P, Q> TranslatePk<P, Q> for Wpkh<P>
where
P: MiniscriptKey,
Q: MiniscriptKey,
{
type Output = Wpkh<Q>;
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, TranslateErr<E>>
where
T: Translator<P, Q, E>,
{
let res = Wpkh::new(t.pk(&self.pk)?);
match res {
Ok(pk) => Ok(pk),
Err(e) => Err(TranslateErr::OuterError(Error::from(e))),
}
}
}