use core::convert::TryFrom;
use core::fmt;
use bitcoin::script::PushBytes;
use bitcoin::{script, Address, Network, ScriptBuf, Weight};
use super::checksum::verify_checksum;
use super::{SortedMultiVec, Wpkh, Wsh};
use crate::descriptor::{write_descriptor, DefiniteDescriptorKey};
use crate::expression::{self, FromTree};
use crate::miniscript::context::ScriptContext;
use crate::miniscript::satisfy::{Placeholder, Satisfaction};
use crate::plan::AssetProvider;
use crate::policy::{semantic, Liftable};
use crate::prelude::*;
use crate::util::{varint_len, witness_to_scriptsig};
use crate::{
push_opcode_size, Error, ForEachKey, FromStrKey, Legacy, Miniscript, MiniscriptKey, Satisfier,
Segwitv0, ToPublicKey, TranslateErr, TranslatePk, Translator,
};
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct Sh<Pk: MiniscriptKey> {
inner: ShInner<Pk>,
}
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub enum ShInner<Pk: MiniscriptKey> {
Wsh(Wsh<Pk>),
Wpkh(Wpkh<Pk>),
SortedMulti(SortedMultiVec<Pk, Legacy>),
Ms(Miniscript<Pk, Legacy>),
}
impl<Pk: MiniscriptKey> Liftable<Pk> for Sh<Pk> {
fn lift(&self) -> Result<semantic::Policy<Pk>, Error> {
match self.inner {
ShInner::Wsh(ref wsh) => wsh.lift(),
ShInner::Wpkh(ref pk) => Ok(semantic::Policy::Key(pk.as_inner().clone())),
ShInner::SortedMulti(ref smv) => smv.lift(),
ShInner::Ms(ref ms) => ms.lift(),
}
}
}
impl<Pk: MiniscriptKey> fmt::Debug for Sh<Pk> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.inner {
ShInner::Wsh(ref wsh_inner) => write!(f, "sh({:?})", wsh_inner),
ShInner::Wpkh(ref pk) => write!(f, "sh({:?})", pk),
ShInner::SortedMulti(ref smv) => write!(f, "sh({:?})", smv),
ShInner::Ms(ref ms) => write!(f, "sh({:?})", ms),
}
}
}
impl<Pk: MiniscriptKey> fmt::Display for Sh<Pk> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.inner {
ShInner::Wsh(ref wsh) => write_descriptor!(f, "sh({:#})", wsh),
ShInner::Wpkh(ref pk) => write_descriptor!(f, "sh({:#})", pk),
ShInner::SortedMulti(ref smv) => write_descriptor!(f, "sh({})", smv),
ShInner::Ms(ref ms) => write_descriptor!(f, "sh({})", ms),
}
}
}
impl<Pk: FromStrKey> crate::expression::FromTree for Sh<Pk> {
fn from_tree(top: &expression::Tree) -> Result<Self, Error> {
if top.name == "sh" && top.args.len() == 1 {
let top = &top.args[0];
let inner = match top.name {
"wsh" => ShInner::Wsh(Wsh::from_tree(top)?),
"wpkh" => ShInner::Wpkh(Wpkh::from_tree(top)?),
"sortedmulti" => ShInner::SortedMulti(SortedMultiVec::from_tree(top)?),
_ => {
let sub = Miniscript::from_tree(top)?;
Legacy::top_level_checks(&sub)?;
ShInner::Ms(sub)
}
};
Ok(Sh { inner })
} else {
Err(Error::Unexpected(format!(
"{}({} args) while parsing sh descriptor",
top.name,
top.args.len(),
)))
}
}
}
impl<Pk: FromStrKey> core::str::FromStr for Sh<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> Sh<Pk> {
pub fn into_inner(self) -> ShInner<Pk> { self.inner }
pub fn as_inner(&self) -> &ShInner<Pk> { &self.inner }
pub fn new(ms: Miniscript<Pk, Legacy>) -> Result<Self, Error> {
Legacy::top_level_checks(&ms)?;
Ok(Self { inner: ShInner::Ms(ms) })
}
pub fn new_sortedmulti(k: usize, pks: Vec<Pk>) -> Result<Self, Error> {
Ok(Self { inner: ShInner::SortedMulti(SortedMultiVec::new(k, pks)?) })
}
pub fn new_wsh(ms: Miniscript<Pk, Segwitv0>) -> Result<Self, Error> {
Ok(Self { inner: ShInner::Wsh(Wsh::new(ms)?) })
}
pub fn new_with_wsh(wsh: Wsh<Pk>) -> Self { Self { inner: ShInner::Wsh(wsh) } }
pub fn sanity_check(&self) -> Result<(), Error> {
match self.inner {
ShInner::Wsh(ref wsh) => wsh.sanity_check()?,
ShInner::Wpkh(ref wpkh) => wpkh.sanity_check()?,
ShInner::SortedMulti(ref smv) => smv.sanity_check()?,
ShInner::Ms(ref ms) => ms.sanity_check()?,
}
Ok(())
}
pub fn new_wsh_sortedmulti(k: usize, pks: Vec<Pk>) -> Result<Self, Error> {
Ok(Self { inner: ShInner::Wsh(Wsh::new_sortedmulti(k, pks)?) })
}
pub fn new_wpkh(pk: Pk) -> Result<Self, Error> {
Ok(Self { inner: ShInner::Wpkh(Wpkh::new(pk)?) })
}
pub fn new_with_wpkh(wpkh: Wpkh<Pk>) -> Self { Self { inner: ShInner::Wpkh(wpkh) } }
pub fn max_weight_to_satisfy(&self) -> Result<Weight, Error> {
let (scriptsig_size, witness_size) = match self.inner {
ShInner::Wsh(ref wsh) => {
let scriptsig_size = 1 + 1 + 1 + 32;
let witness_size = wsh.max_weight_to_satisfy()?;
(scriptsig_size, witness_size)
}
ShInner::SortedMulti(ref smv) => {
let ss = smv.script_size();
let ps = push_opcode_size(ss);
let scriptsig_size = ps + ss + smv.max_satisfaction_size();
(scriptsig_size, Weight::ZERO)
}
ShInner::Wpkh(ref wpkh) => {
let scriptsig_size = 1 + 1 + 1 + 20;
let witness_size = wpkh.max_weight_to_satisfy();
(scriptsig_size, witness_size)
}
ShInner::Ms(ref ms) => {
let ss = ms.script_size();
let ps = push_opcode_size(ss);
let scriptsig_size = ps + ss + ms.max_satisfaction_size()?;
(scriptsig_size, Weight::ZERO)
}
};
let scriptsig_varint_diff = varint_len(scriptsig_size) - varint_len(0);
let wu = Weight::from_vb((scriptsig_varint_diff + scriptsig_size) as u64);
match wu {
Some(w) => Ok(w + witness_size),
None => Err(Error::CouldNotSatisfy),
}
}
#[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."
)]
#[allow(deprecated)]
pub fn max_satisfaction_weight(&self) -> Result<usize, Error> {
Ok(match self.inner {
ShInner::Wsh(ref wsh) => 4 * 35 + wsh.max_satisfaction_weight()?,
ShInner::SortedMulti(ref smv) => {
let ss = smv.script_size();
let ps = push_opcode_size(ss);
let scriptsig_len = ps + ss + smv.max_satisfaction_size();
4 * (varint_len(scriptsig_len) + scriptsig_len)
}
ShInner::Wpkh(ref wpkh) => 4 * 23 + wpkh.max_satisfaction_weight(),
ShInner::Ms(ref ms) => {
let ss = ms.script_size();
let ps = push_opcode_size(ss);
let scriptsig_len = ps + ss + ms.max_satisfaction_size()?;
4 * (varint_len(scriptsig_len) + scriptsig_len)
}
})
}
}
impl<Pk: MiniscriptKey + ToPublicKey> Sh<Pk> {
pub fn script_pubkey(&self) -> ScriptBuf {
match self.inner {
ShInner::Wsh(ref wsh) => wsh.script_pubkey().to_p2sh(),
ShInner::Wpkh(ref wpkh) => wpkh.script_pubkey().to_p2sh(),
ShInner::SortedMulti(ref smv) => smv.encode().to_p2sh(),
ShInner::Ms(ref ms) => ms.encode().to_p2sh(),
}
}
pub fn address(&self, network: Network) -> Address {
let addr = self.address_fallible(network);
assert!(addr.is_ok());
addr.expect("only fails if size > MAX_SCRIPT_ELEMENT_SIZE")
}
fn address_fallible(&self, network: Network) -> Result<Address, Error> {
let script = match self.inner {
ShInner::Wsh(ref wsh) => wsh.script_pubkey(),
ShInner::Wpkh(ref wpkh) => wpkh.script_pubkey(),
ShInner::SortedMulti(ref smv) => smv.encode(),
ShInner::Ms(ref ms) => ms.encode(),
};
let address = Address::p2sh(&script, network)?;
Ok(address)
}
pub fn inner_script(&self) -> ScriptBuf {
match self.inner {
ShInner::Wsh(ref wsh) => wsh.inner_script(),
ShInner::Wpkh(ref wpkh) => wpkh.script_pubkey(),
ShInner::SortedMulti(ref smv) => smv.encode(),
ShInner::Ms(ref ms) => ms.encode(),
}
}
pub fn ecdsa_sighash_script_code(&self) -> ScriptBuf {
match self.inner {
ShInner::Wsh(ref wsh) => wsh.ecdsa_sighash_script_code(),
ShInner::SortedMulti(ref smv) => smv.encode(),
ShInner::Wpkh(ref wpkh) => wpkh.ecdsa_sighash_script_code(),
ShInner::Ms(ref ms) => ms.encode(),
}
}
pub fn unsigned_script_sig(&self) -> ScriptBuf {
match self.inner {
ShInner::Wsh(ref wsh) => {
let witness_script = wsh.inner_script().to_p2wsh();
let push_bytes = <&PushBytes>::try_from(witness_script.as_bytes())
.expect("Witness script is not too large");
script::Builder::new().push_slice(push_bytes).into_script()
}
ShInner::Wpkh(ref wpkh) => {
let redeem_script = wpkh.script_pubkey();
let push_bytes: &PushBytes =
<&PushBytes>::try_from(redeem_script.as_bytes()).expect("Script not too large");
script::Builder::new().push_slice(push_bytes).into_script()
}
ShInner::SortedMulti(..) | ShInner::Ms(..) => ScriptBuf::new(),
}
}
pub fn get_satisfaction<S>(&self, satisfier: S) -> Result<(Vec<Vec<u8>>, ScriptBuf), Error>
where
S: Satisfier<Pk>,
{
let script_sig = self.unsigned_script_sig();
match self.inner {
ShInner::Wsh(ref wsh) => {
let (witness, _) = wsh.get_satisfaction(satisfier)?;
Ok((witness, script_sig))
}
ShInner::Wpkh(ref wpkh) => {
let (witness, _) = wpkh.get_satisfaction(satisfier)?;
Ok((witness, script_sig))
}
ShInner::SortedMulti(ref smv) => {
let mut script_witness = smv.satisfy(satisfier)?;
script_witness.push(smv.encode().into_bytes());
let script_sig = witness_to_scriptsig(&script_witness);
let witness = vec![];
Ok((witness, script_sig))
}
ShInner::Ms(ref ms) => {
let mut script_witness = ms.satisfy(satisfier)?;
script_witness.push(ms.encode().into_bytes());
let script_sig = witness_to_scriptsig(&script_witness);
let witness = vec![];
Ok((witness, script_sig))
}
}
}
pub fn get_satisfaction_mall<S>(&self, satisfier: S) -> Result<(Vec<Vec<u8>>, ScriptBuf), Error>
where
S: Satisfier<Pk>,
{
let script_sig = self.unsigned_script_sig();
match self.inner {
ShInner::Wsh(ref wsh) => {
let (witness, _) = wsh.get_satisfaction_mall(satisfier)?;
Ok((witness, script_sig))
}
ShInner::Ms(ref ms) => {
let mut script_witness = ms.satisfy_malleable(satisfier)?;
script_witness.push(ms.encode().into_bytes());
let script_sig = witness_to_scriptsig(&script_witness);
let witness = vec![];
Ok((witness, script_sig))
}
_ => self.get_satisfaction(satisfier),
}
}
}
impl Sh<DefiniteDescriptorKey> {
pub fn plan_satisfaction<P>(
&self,
provider: &P,
) -> Satisfaction<Placeholder<DefiniteDescriptorKey>>
where
P: AssetProvider<DefiniteDescriptorKey>,
{
match &self.inner {
ShInner::Wsh(ref wsh) => wsh.plan_satisfaction(provider),
ShInner::Wpkh(ref wpkh) => wpkh.plan_satisfaction(provider),
ShInner::SortedMulti(ref smv) => smv.build_template(provider),
ShInner::Ms(ref ms) => ms.build_template(provider),
}
}
pub fn plan_satisfaction_mall<P>(
&self,
provider: &P,
) -> Satisfaction<Placeholder<DefiniteDescriptorKey>>
where
P: AssetProvider<DefiniteDescriptorKey>,
{
match &self.inner {
ShInner::Wsh(ref wsh) => wsh.plan_satisfaction_mall(provider),
ShInner::Ms(ref ms) => ms.build_template_mall(provider),
_ => self.plan_satisfaction(provider),
}
}
}
impl<Pk: MiniscriptKey> ForEachKey<Pk> for Sh<Pk> {
fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, pred: F) -> bool {
match self.inner {
ShInner::Wsh(ref wsh) => wsh.for_each_key(pred),
ShInner::SortedMulti(ref smv) => smv.for_each_key(pred),
ShInner::Wpkh(ref wpkh) => wpkh.for_each_key(pred),
ShInner::Ms(ref ms) => ms.for_each_key(pred),
}
}
}
impl<P, Q> TranslatePk<P, Q> for Sh<P>
where
P: MiniscriptKey,
Q: MiniscriptKey,
{
type Output = Sh<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 {
ShInner::Wsh(ref wsh) => ShInner::Wsh(wsh.translate_pk(t)?),
ShInner::Wpkh(ref wpkh) => ShInner::Wpkh(wpkh.translate_pk(t)?),
ShInner::SortedMulti(ref smv) => ShInner::SortedMulti(smv.translate_pk(t)?),
ShInner::Ms(ref ms) => ShInner::Ms(ms.translate_pk(t)?),
};
Ok(Sh { inner })
}
}