From 03d4bd6ef9ea0bca44ee9522d927ed605a26e676 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 4 May 2022 09:46:00 +1000 Subject: [PATCH 1/9] Remove unnecessary path Using the `bitcoin::` path is necessary for keys but for other well known types, like `Address`, using the path does not add to the readability of the code. (This is subjective.) --- src/descriptor/bare.rs | 12 ++++++------ src/descriptor/mod.rs | 34 ++++++++++++---------------------- src/descriptor/segwitv0.rs | 20 ++++++++++---------- src/descriptor/sh.rs | 22 +++++++++++----------- src/descriptor/tr.rs | 11 ++++------- 5 files changed, 43 insertions(+), 56 deletions(-) diff --git a/src/descriptor/bare.rs b/src/descriptor/bare.rs index bb1ee4702..d871a0956 100644 --- a/src/descriptor/bare.rs +++ b/src/descriptor/bare.rs @@ -22,7 +22,7 @@ use std::fmt; use std::str::FromStr; use bitcoin::blockdata::script; -use bitcoin::{self, Script}; +use bitcoin::{Address, Network, Script}; use super::checksum::{desc_checksum, verify_checksum}; use super::DescriptorTrait; @@ -138,7 +138,7 @@ impl DescriptorTrait for Bare { Ok(()) } - fn address(&self, _network: bitcoin::Network) -> Result + fn address(&self, _network: Network) -> Result where Pk: ToPublicKey, { @@ -258,14 +258,14 @@ impl Pkh { /// Obtain the corresponding script pubkey for this descriptor /// Non failing verion of [`DescriptorTrait::script_pubkey`] for this descriptor pub fn spk(&self) -> Script { - let addr = bitcoin::Address::p2pkh(&self.pk.to_public_key(), bitcoin::Network::Bitcoin); + let addr = Address::p2pkh(&self.pk.to_public_key(), Network::Bitcoin); addr.script_pubkey() } /// Obtain the corresponding script pubkey for this descriptor /// Non failing verion of [`DescriptorTrait::address`] for this descriptor - pub fn addr(&self, network: bitcoin::Network) -> bitcoin::Address { - bitcoin::Address::p2pkh(&self.pk.to_public_key(), network) + pub fn addr(&self, network: Network) -> Address { + Address::p2pkh(&self.pk.to_public_key(), network) } /// Obtain the underlying miniscript for this descriptor @@ -344,7 +344,7 @@ impl DescriptorTrait for Pkh { Ok(()) } - fn address(&self, network: bitcoin::Network) -> Result + fn address(&self, network: Network) -> Result where Pk: ToPublicKey, { diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index fb6a04c65..d78ef3f71 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -31,7 +31,7 @@ use std::sync::Arc; use bitcoin::blockdata::witness::Witness; use bitcoin::util::address::WitnessVersion; -use bitcoin::{self, secp256k1, Script}; +use bitcoin::{self, secp256k1, Address, Network, Script, TxIn}; use self::checksum::verify_checksum; use crate::miniscript::{Legacy, Miniscript, Segwitv0}; @@ -93,7 +93,7 @@ pub trait DescriptorTrait { /// Some descriptors like pk() don't have any address. /// Errors: /// - On raw/bare descriptors that don't have any address - fn address(&self, network: bitcoin::Network) -> Result + fn address(&self, network: Network) -> Result where Pk: ToPublicKey; @@ -142,7 +142,7 @@ pub trait DescriptorTrait { /// Attempts to produce a non-malleable satisfying witness and scriptSig to spend an /// output controlled by the given descriptor; add the data to a given /// `TxIn` output. - fn satisfy(&self, txin: &mut bitcoin::TxIn, satisfier: S) -> Result<(), Error> + fn satisfy(&self, txin: &mut TxIn, satisfier: S) -> Result<(), Error> where Pk: ToPublicKey, S: Satisfier, @@ -487,7 +487,7 @@ impl DescriptorTrait for Descriptor { } } /// Computes the Bitcoin address of the descriptor, if one exists - fn address(&self, network: bitcoin::Network) -> Result + fn address(&self, network: Network) -> Result where Pk: ToPublicKey, { @@ -971,16 +971,14 @@ mod tests { ) ); assert_eq!( - bare.address(bitcoin::Network::Bitcoin) - .unwrap_err() - .to_string(), + bare.address(Network::Bitcoin).unwrap_err().to_string(), "Bare descriptors don't have address" ); let pk = StdDescriptor::from_str(TEST_PK).unwrap(); assert_eq!( pk.script_pubkey(), - bitcoin::Script::from(vec![ + Script::from(vec![ 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xac, @@ -1007,7 +1005,7 @@ mod tests { .into_script() ); assert_eq!( - pkh.address(bitcoin::Network::Bitcoin,).unwrap().to_string(), + pkh.address(Network::Bitcoin,).unwrap().to_string(), "1D7nRvrRgzCg9kYBwhPH3j3Gs6SmsRg3Wq" ); @@ -1028,9 +1026,7 @@ mod tests { .into_script() ); assert_eq!( - wpkh.address(bitcoin::Network::Bitcoin,) - .unwrap() - .to_string(), + wpkh.address(Network::Bitcoin,).unwrap().to_string(), "bc1qsn57m9drscflq5nl76z6ny52hck5w4x5wqd9yt" ); @@ -1052,10 +1048,7 @@ mod tests { .into_script() ); assert_eq!( - shwpkh - .address(bitcoin::Network::Bitcoin,) - .unwrap() - .to_string(), + shwpkh.address(Network::Bitcoin,).unwrap().to_string(), "3PjMEzoveVbvajcnDDuxcJhsuqPHgydQXq" ); @@ -1077,7 +1070,7 @@ mod tests { .into_script() ); assert_eq!( - sh.address(bitcoin::Network::Bitcoin,).unwrap().to_string(), + sh.address(Network::Bitcoin,).unwrap().to_string(), "3HDbdvM9CQ6ASnQFUkWw6Z4t3qNwMesJE9" ); @@ -1103,7 +1096,7 @@ mod tests { .into_script() ); assert_eq!( - wsh.address(bitcoin::Network::Bitcoin,).unwrap().to_string(), + wsh.address(Network::Bitcoin,).unwrap().to_string(), "bc1qlymeahyfsv2jm3upw3urqp6m65ufde9seedl7umh0lth6yjt5zzsk33tv6" ); @@ -1125,10 +1118,7 @@ mod tests { .into_script() ); assert_eq!( - shwsh - .address(bitcoin::Network::Bitcoin,) - .unwrap() - .to_string(), + shwsh.address(Network::Bitcoin,).unwrap().to_string(), "38cTksiyPT2b1uGRVbVqHdDhW9vKs84N6Z" ); } diff --git a/src/descriptor/segwitv0.rs b/src/descriptor/segwitv0.rs index 4c8d8d003..27f5af8e0 100644 --- a/src/descriptor/segwitv0.rs +++ b/src/descriptor/segwitv0.rs @@ -19,7 +19,7 @@ use std::fmt; use std::str::FromStr; -use bitcoin::{self, Script}; +use bitcoin::{self, Address, Network, Script}; use super::checksum::{desc_checksum, verify_checksum}; use super::{DescriptorTrait, SortedMultiVec}; @@ -85,10 +85,10 @@ impl Wsh { /// Obtain the corresponding script pubkey for this descriptor /// Non failing verion of [`DescriptorTrait::address`] for this descriptor - pub fn addr(&self, network: bitcoin::Network) -> bitcoin::Address { + pub fn addr(&self, network: Network) -> Address { match self.inner { - WshInner::SortedMulti(ref smv) => bitcoin::Address::p2wsh(&smv.encode(), network), - WshInner::Ms(ref ms) => bitcoin::Address::p2wsh(&ms.encode(), network), + WshInner::SortedMulti(ref smv) => Address::p2wsh(&smv.encode(), network), + WshInner::Ms(ref ms) => Address::p2wsh(&ms.encode(), network), } } @@ -197,7 +197,7 @@ impl DescriptorTrait for Wsh { Ok(()) } - fn address(&self, network: bitcoin::Network) -> Result + fn address(&self, network: Network) -> Result where Pk: ToPublicKey, { @@ -355,15 +355,15 @@ impl Wpkh { /// Obtain the corresponding script pubkey for this descriptor /// Non failing verion of [`DescriptorTrait::script_pubkey`] for this descriptor pub fn spk(&self) -> Script { - let addr = bitcoin::Address::p2wpkh(&self.pk.to_public_key(), bitcoin::Network::Bitcoin) + let addr = Address::p2wpkh(&self.pk.to_public_key(), Network::Bitcoin) .expect("wpkh descriptors have compressed keys"); addr.script_pubkey() } /// Obtain the corresponding script pubkey for this descriptor /// Non failing verion of [`DescriptorTrait::address`] for this descriptor - pub fn addr(&self, network: bitcoin::Network) -> bitcoin::Address { - bitcoin::Address::p2wpkh(&self.pk.to_public_key(), network) + pub fn addr(&self, network: Network) -> Address { + Address::p2wpkh(&self.pk.to_public_key(), network) .expect("Rust Miniscript types don't allow uncompressed pks in segwit descriptors") } @@ -380,7 +380,7 @@ impl Wpkh { // the previous txo's scriptPubKey. // The item 5: // - For P2WPKH witness program, the scriptCode is `0x1976a914{20-byte-pubkey-hash}88ac`. - let addr = bitcoin::Address::p2pkh(&self.pk.to_public_key(), bitcoin::Network::Bitcoin); + let addr = Address::p2pkh(&self.pk.to_public_key(), Network::Bitcoin); addr.script_pubkey() } } @@ -454,7 +454,7 @@ impl DescriptorTrait for Wpkh { } } - fn address(&self, network: bitcoin::Network) -> Result + fn address(&self, network: Network) -> Result where Pk: ToPublicKey, { diff --git a/src/descriptor/sh.rs b/src/descriptor/sh.rs index 5f834ea92..68cc5666b 100644 --- a/src/descriptor/sh.rs +++ b/src/descriptor/sh.rs @@ -22,7 +22,7 @@ use std::fmt; use std::str::FromStr; use bitcoin::blockdata::script; -use bitcoin::{self, Script}; +use bitcoin::{Address, Network, Script}; use super::checksum::{desc_checksum, verify_checksum}; use super::{DescriptorTrait, SortedMultiVec, Wpkh, Wsh}; @@ -219,19 +219,19 @@ impl Sh { /// Obtain the corresponding script pubkey for this descriptor /// Non failing verion of [`DescriptorTrait::address`] for this descriptor - pub fn addr(&self, network: bitcoin::Network) -> bitcoin::Address { + pub fn addr(&self, network: Network) -> Address { match self.inner { ShInner::Wsh(ref wsh) => { - bitcoin::Address::p2sh(&wsh.spk(), network).expect("Size checked in Miniscript") + Address::p2sh(&wsh.spk(), network).expect("Size checked in Miniscript") } ShInner::Wpkh(ref wpkh) => { - bitcoin::Address::p2sh(&wpkh.spk(), network).expect("Size checked in Miniscript") + Address::p2sh(&wpkh.spk(), network).expect("Size checked in Miniscript") } ShInner::SortedMulti(ref smv) => { - bitcoin::Address::p2sh(&smv.encode(), network).expect("Size checked in Miniscript") + Address::p2sh(&smv.encode(), network).expect("Size checked in Miniscript") } ShInner::Ms(ref ms) => { - bitcoin::Address::p2sh(&ms.encode(), network).expect("Size checked in Miniscript") + Address::p2sh(&ms.encode(), network).expect("Size checked in Miniscript") } } } @@ -273,15 +273,15 @@ impl DescriptorTrait for Sh { Ok(()) } - fn address(&self, network: bitcoin::Network) -> Result + fn address(&self, network: Network) -> Result where Pk: ToPublicKey, { match self.inner { - ShInner::Wsh(ref wsh) => Ok(bitcoin::Address::p2sh(&wsh.spk(), network)?), - ShInner::Wpkh(ref wpkh) => Ok(bitcoin::Address::p2sh(&wpkh.spk(), network)?), - ShInner::SortedMulti(ref smv) => Ok(bitcoin::Address::p2sh(&smv.encode(), network)?), - ShInner::Ms(ref ms) => Ok(bitcoin::Address::p2sh(&ms.encode(), network)?), + ShInner::Wsh(ref wsh) => Ok(Address::p2sh(&wsh.spk(), network)?), + ShInner::Wpkh(ref wpkh) => Ok(Address::p2sh(&wpkh.spk(), network)?), + ShInner::SortedMulti(ref smv) => Ok(Address::p2sh(&smv.encode(), network)?), + ShInner::Ms(ref ms) => Ok(Address::p2sh(&ms.encode(), network)?), } } diff --git a/src/descriptor/tr.rs b/src/descriptor/tr.rs index 4a3e6a166..8974784b0 100644 --- a/src/descriptor/tr.rs +++ b/src/descriptor/tr.rs @@ -10,7 +10,7 @@ use bitcoin::util::taproot::{ LeafVersion, TaprootBuilder, TaprootBuilderError, TaprootSpendInfo, TAPROOT_CONTROL_BASE_SIZE, TAPROOT_CONTROL_MAX_NODE_COUNT, TAPROOT_CONTROL_NODE_SIZE, }; -use bitcoin::{self, secp256k1, Script}; +use bitcoin::{secp256k1, Address, Network, Script}; use super::checksum::{desc_checksum, verify_checksum}; use crate::expression::{self, FromTree}; @@ -286,12 +286,9 @@ impl Tr { /// Obtain the corresponding script pubkey for this descriptor /// Same as[`DescriptorTrait::address`] for this descriptor - pub fn addr(&self, network: bitcoin::Network) -> Result { + pub fn addr(&self, network: Network) -> Result { let spend_info = self.spend_info(); - Ok(bitcoin::Address::p2tr_tweaked( - spend_info.output_key(), - network, - )) + Ok(Address::p2tr_tweaked(spend_info.output_key(), network)) } } @@ -558,7 +555,7 @@ impl DescriptorTrait for Tr { Ok(()) } - fn address(&self, network: bitcoin::Network) -> Result + fn address(&self, network: Network) -> Result where Pk: ToPublicKey, { From 498060477a2477153f6c05fd5054af8d5e3606a4 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 17 May 2022 10:31:07 +1000 Subject: [PATCH 2/9] Delete the pretaproot module In preparation for removing the `DescriptorTrait` remove the pretaproot module. This is possible because removing the trait will resolve the error return issues that the taproot module exists to solve. --- src/descriptor/mod.rs | 40 ----- src/descriptor/pretaproot.rs | 282 ----------------------------------- src/lib.rs | 2 - 3 files changed, 324 deletions(-) delete mode 100644 src/descriptor/pretaproot.rs diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index d78ef3f71..bcb7e3a7c 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -40,9 +40,6 @@ use crate::{ ToPublicKey, TranslatePk, TranslatePk2, }; -// Directly export from lib.rs, exporting the trait here causes conflicts in this file -pub(crate) mod pretaproot; - mod bare; mod segwitv0; mod sh; @@ -398,43 +395,6 @@ impl Descriptor { Descriptor::Tr(ref _tr) => DescriptorType::Tr, } } - - /// . - /// Convert a Descriptor into [`pretaproot::PreTaprootDescriptor`] - /// # Examples - /// - /// ``` - /// use std::str::FromStr; - /// use miniscript::descriptor::Descriptor; - /// use miniscript::{PreTaprootDescriptor, PreTaprootDescriptorTrait}; - /// use miniscript::bitcoin; - /// - /// // A descriptor with a string generic - /// let desc = Descriptor::::from_str("wpkh(02e18f242c8b0b589bfffeac30e1baa80a60933a649c7fb0f1103e78fbf58aa0ed)") - /// .expect("Valid segwitv0 descriptor"); - /// let pre_tap_desc = desc.into_pre_taproot_desc().expect("Wsh is pre taproot"); - /// - /// // Now the script code and explicit script no longer fail on longer fail - /// // on PreTaprootDescriptor using PreTaprootDescriptorTrait - /// let script_code = pre_tap_desc.script_code(); - /// assert_eq!(script_code.to_string(), - /// "Script(OP_DUP OP_HASH160 OP_PUSHBYTES_20 62107d047e8818b594303fe0657388cc4fc8771f OP_EQUALVERIFY OP_CHECKSIG)" - /// ); - /// ``` - /// - /// # Errors - /// - /// This function will return an error if descriptor is not a pre taproot descriptor. - pub fn into_pre_taproot_desc(self) -> Result, Self> { - match self { - Descriptor::Bare(bare) => Ok(pretaproot::PreTaprootDescriptor::Bare(bare)), - Descriptor::Pkh(pkh) => Ok(pretaproot::PreTaprootDescriptor::Pkh(pkh)), - Descriptor::Wpkh(wpkh) => Ok(pretaproot::PreTaprootDescriptor::Wpkh(wpkh)), - Descriptor::Sh(sh) => Ok(pretaproot::PreTaprootDescriptor::Sh(sh)), - Descriptor::Wsh(wsh) => Ok(pretaproot::PreTaprootDescriptor::Wsh(wsh)), - Descriptor::Tr(tr) => Err(Descriptor::Tr(tr)), - } - } } impl TranslatePk for Descriptor

diff --git a/src/descriptor/pretaproot.rs b/src/descriptor/pretaproot.rs deleted file mode 100644 index e8c67ff5c..000000000 --- a/src/descriptor/pretaproot.rs +++ /dev/null @@ -1,282 +0,0 @@ -use std::fmt; -use std::str::{self, FromStr}; - -use bitcoin::{self, Script}; - -use super::checksum::verify_checksum; -use super::{Bare, Pkh, Sh, Wpkh, Wsh}; -use crate::{expression, DescriptorTrait, Error, MiniscriptKey, Satisfier, ToPublicKey}; - -/// Script descriptor -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum PreTaprootDescriptor { - /// Bare descriptor - Bare(Bare), - /// Pay-to-PubKey-Hash - Pkh(Pkh), - /// Pay-to-Witness-PubKey-Hash - Wpkh(Wpkh), - /// Pay-to-ScriptHash(includes nested wsh/wpkh/sorted multi) - Sh(Sh), - /// Pay-to-Witness-ScriptHash with Segwitv0 context - Wsh(Wsh), -} - -impl DescriptorTrait for PreTaprootDescriptor { - /// Whether the descriptor is safe - /// Checks whether all the spend paths in the descriptor are possible - /// on the bitcoin network under the current standardness and consensus rules - /// Also checks whether the descriptor requires signauture on all spend paths - /// And whether the script is malleable. - /// In general, all the guarantees of miniscript hold only for safe scripts. - /// All the analysis guarantees of miniscript only hold safe scripts. - /// The signer may not be able to find satisfactions even if one exists - 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(), - } - } - /// Computes the Bitcoin address of the descriptor, if one exists - fn address(&self, network: bitcoin::Network) -> Result - 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), - } - } - - /// Computes the scriptpubkey of the descriptor - 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(), - } - } - - /// Computes the scriptSig that will be in place for an unsigned - /// input spending an output with this descriptor. For pre-segwit - /// descriptors, which use the scriptSig for signatures, this - /// returns the empty script. - /// - /// This is used in Segwit transactions to produce an unsigned - /// transaction whose txid will not change during signing (since - /// only the witness data will change). - 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(), - } - } - - /// Computes the "witness script" of the descriptor, i.e. the underlying - /// script before any hashing is done. For `Bare`, `Pkh` and `Wpkh` this - /// is the scriptPubkey; for `ShWpkh` and `Sh` this is the redeemScript; - /// for the others it is the witness script. - /// Errors: - /// - When the descriptor is Tr - fn explicit_script(&self) -> Result - 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(), - } - } - - /// Returns satisfying non-malleable witness and scriptSig to spend an - /// output controlled by the given descriptor if it possible to - /// construct one using the satisfier S. - fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, Script), Error> - where - Pk: ToPublicKey, - S: Satisfier, - { - 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), - } - } - - /// Returns a possilbly mallable satisfying non-malleable witness and scriptSig to spend an - /// output controlled by the given descriptor if it possible to - /// construct one using the satisfier S. - fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, Script), Error> - where - Pk: ToPublicKey, - S: Satisfier, - { - 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), - } - } - - /// Computes an upper bound on the weight of a satisfying witness to the - /// transaction. Assumes all signatures are 73 bytes, including push opcode - /// and sighash suffix. Includes the weight of the VarInts encoding the - /// scriptSig and witness stack length. - fn max_satisfaction_weight(&self) -> Result { - 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(), - } - } - - /// Get the `scriptCode` of a transaction output. - /// - /// The `scriptCode` is the Script of the previous transaction output being serialized in the - /// sighash when evaluating a `CHECKSIG` & co. OP code. - /// Returns Error for Tr descriptors - fn script_code(&self) -> Result - 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 expression::FromTree for PreTaprootDescriptor -where - Pk: MiniscriptKey + str::FromStr, - Pk::Hash: str::FromStr, - ::Err: ToString, - <::Hash as FromStr>::Err: ToString, -{ - /// Parse an expression tree into a descriptor - fn from_tree(top: &expression::Tree) -> Result, 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 FromStr for PreTaprootDescriptor -where - Pk: MiniscriptKey + str::FromStr, - Pk::Hash: str::FromStr, - ::Err: ToString, - <::Hash as FromStr>::Err: ToString, -{ - type Err = Error; - - fn from_str(s: &str) -> Result, Error> { - let desc_str = verify_checksum(s)?; - let top = expression::Tree::from_str(desc_str)?; - expression::FromTree::from_tree(&top) - } -} - -impl fmt::Debug for PreTaprootDescriptor { - 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 fmt::Display for PreTaprootDescriptor { - 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"); - -// Have the trait in a separate module to avoid conflicts -pub(crate) mod traits { - use bitcoin::Script; - - use super::PreTaprootDescriptor; - use crate::descriptor::{Pkh, Sh, Wpkh, Wsh}; - use crate::{DescriptorTrait, MiniscriptKey, ToPublicKey}; - - /// A general trait for Pre taproot bitcoin descriptor. - /// Similar to [`DescriptorTrait`], but `explicit_script` and `script_code` methods cannot fail - pub trait PreTaprootDescriptorTrait: DescriptorTrait { - /// Same as [`DescriptorTrait::explicit_script`], but a non failing version. - /// All PreTaproot descriptors have a unique explicit script - fn explicit_script(&self) -> Script - where - Pk: ToPublicKey, - { - // This expect can technically be avoided if we implement this for types, but - // having this expect saves lots of LoC because of default implementation - >::explicit_script(self) - .expect("Pre taproot descriptor have explicit script") - } - - /// Same as [`DescriptorTrait::script_code`], but a non failing version. - /// All PreTaproot descriptors have a script code - fn script_code(&self) -> Script - where - Pk: ToPublicKey, - { - >::script_code(self) - .expect("Pre taproot descriptor have non-failing script code") - } - } - - impl PreTaprootDescriptorTrait for Pkh {} - - impl PreTaprootDescriptorTrait for Sh {} - - impl PreTaprootDescriptorTrait for Wpkh {} - - impl PreTaprootDescriptorTrait for Wsh {} - - impl PreTaprootDescriptorTrait for PreTaprootDescriptor {} -} diff --git a/src/lib.rs b/src/lib.rs index 6a8019b33..d46450b5a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -114,8 +114,6 @@ use std::{error, fmt, hash, str}; use bitcoin::blockdata::{opcodes, script}; use bitcoin::hashes::{hash160, sha256, Hash}; -pub use crate::descriptor::pretaproot::traits::PreTaprootDescriptorTrait; -pub use crate::descriptor::pretaproot::PreTaprootDescriptor; pub use crate::descriptor::{Descriptor, DescriptorPublicKey, DescriptorTrait}; pub use crate::interpreter::Interpreter; pub use crate::miniscript::context::{BareCtx, Legacy, ScriptContext, Segwitv0, Tap}; From 4a9e20f9a31e45fcb6c228fb58d6bbc4ed6b6888 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 17 May 2022 10:47:41 +1000 Subject: [PATCH 3/9] Remove sanity_check from DescriptorTrait In preparation for removing the `DescriptorTrait` move the `sanity_check` trait methods onto each individual descriptor. --- src/descriptor/bare.rs | 15 +++++------- src/descriptor/mod.rs | 48 ++++++++++++++++---------------------- src/descriptor/segwitv0.rs | 38 ++++++++++++++++-------------- src/descriptor/sh.rs | 21 +++++++++-------- src/descriptor/tr.rs | 15 ++++++------ 5 files changed, 65 insertions(+), 72 deletions(-) diff --git a/src/descriptor/bare.rs b/src/descriptor/bare.rs index d871a0956..9e52a7570 100644 --- a/src/descriptor/bare.rs +++ b/src/descriptor/bare.rs @@ -60,6 +60,12 @@ impl Bare { pub fn as_inner(&self) -> &Miniscript { &self.ms } + + /// Checks whether the descriptor is safe. + pub fn sanity_check(&self) -> Result<(), Error> { + self.ms.sanity_check()?; + Ok(()) + } } impl Bare { @@ -133,11 +139,6 @@ where } impl DescriptorTrait for Bare { - fn sanity_check(&self) -> Result<(), Error> { - self.ms.sanity_check()?; - Ok(()) - } - fn address(&self, _network: Network) -> Result where Pk: ToPublicKey, @@ -340,10 +341,6 @@ where } impl DescriptorTrait for Pkh { - fn sanity_check(&self) -> Result<(), Error> { - Ok(()) - } - fn address(&self, network: Network) -> Result where Pk: ToPublicKey, diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index bcb7e3a7c..f18e3effb 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -76,16 +76,6 @@ pub type KeyMap = HashMap; // because of traits cannot know underlying generic of Self. // Thus, we must implement additional trait for translate function pub trait DescriptorTrait { - /// Whether the descriptor is safe - /// Checks whether all the spend paths in the descriptor are possible - /// on the bitcoin network under the current standardness and consensus rules - /// Also checks whether the descriptor requires signauture on all spend paths - /// And whether the script is malleable. - /// In general, all the guarantees of miniscript hold only for safe scripts. - /// All the analysis guarantees of miniscript only hold safe scripts. - /// The signer may not be able to find satisfactions even if one exists - fn sanity_check(&self) -> Result<(), Error>; - /// Computes the Bitcoin address of the descriptor, if one exists /// Some descriptors like pk() don't have any address. /// Errors: @@ -395,6 +385,26 @@ impl Descriptor { Descriptor::Tr(ref _tr) => DescriptorType::Tr, } } + + /// Checks whether the descriptor is safe. + /// + /// Checks whether all the spend paths in the descriptor are possible on the + /// bitcoin network under the current standardness and consensus rules. Also + /// checks whether the descriptor requires signatures on all spend paths and + /// whether the script is malleable. + /// + /// In general, all the guarantees of miniscript hold only for safe scripts. + /// The signer may not be able to find satisfactions even if one exists. + pub fn sanity_check(&self) -> Result<(), Error> { + match *self { + Descriptor::Bare(ref bare) => bare.sanity_check(), + Descriptor::Pkh(_) => Ok(()), + Descriptor::Wpkh(ref wpkh) => wpkh.sanity_check(), + Descriptor::Wsh(ref wsh) => wsh.sanity_check(), + Descriptor::Sh(ref sh) => sh.sanity_check(), + Descriptor::Tr(ref tr) => tr.sanity_check(), + } + } } impl TranslatePk for Descriptor

@@ -428,24 +438,6 @@ where } impl DescriptorTrait for Descriptor { - /// Whether the descriptor is safe - /// Checks whether all the spend paths in the descriptor are possible - /// on the bitcoin network under the current standardness and consensus rules - /// Also checks whether the descriptor requires signauture on all spend paths - /// And whether the script is malleable. - /// In general, all the guarantees of miniscript hold only for safe scripts. - /// All the analysis guarantees of miniscript only hold safe scripts. - /// The signer may not be able to find satisfactions even if one exists - fn sanity_check(&self) -> Result<(), Error> { - match *self { - Descriptor::Bare(ref bare) => bare.sanity_check(), - Descriptor::Pkh(ref pkh) => pkh.sanity_check(), - Descriptor::Wpkh(ref wpkh) => wpkh.sanity_check(), - Descriptor::Wsh(ref wsh) => wsh.sanity_check(), - Descriptor::Sh(ref sh) => sh.sanity_check(), - Descriptor::Tr(ref tr) => tr.sanity_check(), - } - } /// Computes the Bitcoin address of the descriptor, if one exists fn address(&self, network: Network) -> Result where diff --git a/src/descriptor/segwitv0.rs b/src/descriptor/segwitv0.rs index 27f5af8e0..71af6821e 100644 --- a/src/descriptor/segwitv0.rs +++ b/src/descriptor/segwitv0.rs @@ -74,6 +74,15 @@ impl Wsh { WshInner::Ms(ref ms) => format!("wsh({})", ms), } } + + /// Checks whether the descriptor is safe. + 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(()) + } } impl Wsh { @@ -189,14 +198,6 @@ where } impl DescriptorTrait for Wsh { - fn sanity_check(&self) -> Result<(), Error> { - match self.inner { - WshInner::SortedMulti(ref smv) => smv.sanity_check()?, - WshInner::Ms(ref ms) => ms.sanity_check()?, - } - Ok(()) - } - fn address(&self, network: Network) -> Result where Pk: ToPublicKey, @@ -349,6 +350,17 @@ impl Wpkh { pub fn to_string_no_checksum(&self) -> String { format!("wpkh({})", self.pk) } + + /// Checks whether the descriptor is safe. + pub fn sanity_check(&self) -> Result<(), Error> { + if self.pk.is_uncompressed() { + Err(Error::ContextError(ScriptContextError::CompressedOnly( + self.pk.to_string(), + ))) + } else { + Ok(()) + } + } } impl Wpkh { @@ -444,16 +456,6 @@ where } impl DescriptorTrait for Wpkh { - fn sanity_check(&self) -> Result<(), Error> { - if self.pk.is_uncompressed() { - Err(Error::ContextError(ScriptContextError::CompressedOnly( - self.pk.to_string(), - ))) - } else { - Ok(()) - } - } - fn address(&self, network: Network) -> Result where Pk: ToPublicKey, diff --git a/src/descriptor/sh.rs b/src/descriptor/sh.rs index 68cc5666b..74b123eeb 100644 --- a/src/descriptor/sh.rs +++ b/src/descriptor/sh.rs @@ -180,6 +180,17 @@ impl Sh { } } + /// Checks whether the descriptor is safe. + 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(()) + } + /// Create a new p2sh wrapped wsh sortedmulti descriptor from threshold /// `k` and Vec of `pks` pub fn new_wsh_sortedmulti(k: usize, pks: Vec) -> Result { @@ -263,16 +274,6 @@ impl Sh { } impl DescriptorTrait for Sh { - 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(()) - } - fn address(&self, network: Network) -> Result where Pk: ToPublicKey, diff --git a/src/descriptor/tr.rs b/src/descriptor/tr.rs index 8974784b0..51001f0ea 100644 --- a/src/descriptor/tr.rs +++ b/src/descriptor/tr.rs @@ -270,6 +270,14 @@ impl Tr { *self.spend_info.lock().expect("Lock poisoned") = Some(Arc::clone(&spend_info)); spend_info } + + /// Checks whether the descriptor is safe. + pub fn sanity_check(&self) -> Result<(), Error> { + for (_depth, ms) in self.iter_scripts() { + ms.sanity_check()?; + } + Ok(()) + } } impl Tr { @@ -548,13 +556,6 @@ impl Liftable for Tr { } impl DescriptorTrait for Tr { - fn sanity_check(&self) -> Result<(), Error> { - for (_depth, ms) in self.iter_scripts() { - ms.sanity_check()?; - } - Ok(()) - } - fn address(&self, network: Network) -> Result where Pk: ToPublicKey, From 3d0b11254c44e32615077f1f026b148e025c32d2 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 17 May 2022 10:56:04 +1000 Subject: [PATCH 4/9] Remove address from DescriptorTrait In preparation for removing the `DescriptorTrait` move the `address` trait methods onto each individual descriptor. Replaces the `addr` method. --- examples/htlc.rs | 3 +-- examples/xpub_descriptors.rs | 2 +- src/descriptor/bare.rs | 19 ++------------ src/descriptor/mod.rs | 42 ++++++++++++++----------------- src/descriptor/segwitv0.rs | 24 +++--------------- src/descriptor/sh.rs | 48 ++++++++++++++---------------------- src/descriptor/tr.rs | 14 +++-------- 7 files changed, 49 insertions(+), 103 deletions(-) diff --git a/examples/htlc.rs b/examples/htlc.rs index c669823aa..3db169773 100644 --- a/examples/htlc.rs +++ b/examples/htlc.rs @@ -19,7 +19,6 @@ use std::str::FromStr; use bitcoin::Network; use miniscript::descriptor::Wsh; use miniscript::policy::{Concrete, Liftable}; -use miniscript::DescriptorTrait; fn main() { // HTLC policy with 10:1 odds for happy (co-operative) case compared to uncooperative case. @@ -66,7 +65,7 @@ fn main() { // Get the address for this Wsh descriptor.v assert_eq!( - format!("{}", htlc_descriptor.address(Network::Bitcoin).unwrap()), + format!("{}", htlc_descriptor.address(Network::Bitcoin)), "bc1qmpfcw7he9z5d9ftfe8qw699azmm2sr8fen903fs4plv007yx0t3qxfmqv5" ); } diff --git a/examples/xpub_descriptors.rs b/examples/xpub_descriptors.rs index ce6c48d02..c66f26307 100644 --- a/examples/xpub_descriptors.rs +++ b/examples/xpub_descriptors.rs @@ -18,7 +18,7 @@ use std::str::FromStr; use miniscript::bitcoin::secp256k1::{Secp256k1, Verification}; use miniscript::bitcoin::{Address, Network}; -use miniscript::{Descriptor, DescriptorPublicKey, DescriptorTrait, TranslatePk2}; +use miniscript::{Descriptor, DescriptorPublicKey, TranslatePk2}; const XPUB_1: &str = "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB"; const XPUB_2: &str = "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH"; diff --git a/src/descriptor/bare.rs b/src/descriptor/bare.rs index 9e52a7570..e5a447cf0 100644 --- a/src/descriptor/bare.rs +++ b/src/descriptor/bare.rs @@ -139,13 +139,6 @@ where } impl DescriptorTrait for Bare { - fn address(&self, _network: Network) -> Result - where - Pk: ToPublicKey, - { - Err(Error::BareDescriptorAddr) - } - fn script_pubkey(&self) -> Script where Pk: ToPublicKey, @@ -263,9 +256,8 @@ impl Pkh { addr.script_pubkey() } - /// Obtain the corresponding script pubkey for this descriptor - /// Non failing verion of [`DescriptorTrait::address`] for this descriptor - pub fn addr(&self, network: Network) -> Address { + /// Obtains the corresponding script pubkey for this descriptor. + pub fn address(&self, network: Network) -> Address { Address::p2pkh(&self.pk.to_public_key(), network) } @@ -341,13 +333,6 @@ where } impl DescriptorTrait for Pkh { - fn address(&self, network: Network) -> Result - where - Pk: ToPublicKey, - { - Ok(self.addr(network)) - } - fn script_pubkey(&self) -> Script where Pk: ToPublicKey, diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index f18e3effb..0794a11f2 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -76,14 +76,6 @@ pub type KeyMap = HashMap; // because of traits cannot know underlying generic of Self. // Thus, we must implement additional trait for translate function pub trait DescriptorTrait { - /// Computes the Bitcoin address of the descriptor, if one exists - /// Some descriptors like pk() don't have any address. - /// Errors: - /// - On raw/bare descriptors that don't have any address - fn address(&self, network: Network) -> Result - where - Pk: ToPublicKey; - /// Computes the scriptpubkey of the descriptor fn script_pubkey(&self) -> Script where @@ -407,6 +399,25 @@ impl Descriptor { } } +impl Descriptor { + /// Computes the Bitcoin address of the descriptor, if one exists + /// + /// Some descriptors like pk() don't have any address. + /// + /// # Errors + /// For raw/bare descriptors that don't have any address. + pub fn address(&self, network: Network) -> Result { + match *self { + Descriptor::Bare(_) => Err(Error::BareDescriptorAddr), + Descriptor::Pkh(ref pkh) => Ok(pkh.address(network)), + Descriptor::Wpkh(ref wpkh) => Ok(wpkh.address(network)), + Descriptor::Wsh(ref wsh) => Ok(wsh.address(network)), + Descriptor::Sh(ref sh) => Ok(sh.address(network)), + Descriptor::Tr(ref tr) => Ok(tr.address(network)), + } + } +} + impl TranslatePk for Descriptor

where P: MiniscriptKey, @@ -438,21 +449,6 @@ where } impl DescriptorTrait for Descriptor { - /// Computes the Bitcoin address of the descriptor, if one exists - fn address(&self, network: Network) -> Result - where - Pk: ToPublicKey, - { - match *self { - Descriptor::Bare(ref bare) => bare.address(network), - Descriptor::Pkh(ref pkh) => pkh.address(network), - Descriptor::Wpkh(ref wpkh) => wpkh.address(network), - Descriptor::Wsh(ref wsh) => wsh.address(network), - Descriptor::Sh(ref sh) => sh.address(network), - Descriptor::Tr(ref tr) => tr.address(network), - } - } - /// Computes the scriptpubkey of the descriptor fn script_pubkey(&self) -> Script where diff --git a/src/descriptor/segwitv0.rs b/src/descriptor/segwitv0.rs index 71af6821e..5103b4aa6 100644 --- a/src/descriptor/segwitv0.rs +++ b/src/descriptor/segwitv0.rs @@ -92,9 +92,8 @@ impl Wsh { self.inner_script().to_v0_p2wsh() } - /// Obtain the corresponding script pubkey for this descriptor - /// Non failing verion of [`DescriptorTrait::address`] for this descriptor - pub fn addr(&self, network: Network) -> Address { + /// Obtains the corresponding script pubkey for this descriptor. + 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), @@ -198,13 +197,6 @@ where } impl DescriptorTrait for Wsh { - fn address(&self, network: Network) -> Result - where - Pk: ToPublicKey, - { - Ok(self.addr(network)) - } - fn script_pubkey(&self) -> Script where Pk: ToPublicKey, @@ -372,9 +364,8 @@ impl Wpkh { addr.script_pubkey() } - /// Obtain the corresponding script pubkey for this descriptor - /// Non failing verion of [`DescriptorTrait::address`] for this descriptor - pub fn addr(&self, network: Network) -> Address { + /// Obtains the corresponding script pubkey for this descriptor. + pub fn address(&self, network: Network) -> Address { Address::p2wpkh(&self.pk.to_public_key(), network) .expect("Rust Miniscript types don't allow uncompressed pks in segwit descriptors") } @@ -456,13 +447,6 @@ where } impl DescriptorTrait for Wpkh { - fn address(&self, network: Network) -> Result - where - Pk: ToPublicKey, - { - Ok(self.addr(network)) - } - fn script_pubkey(&self) -> Script where Pk: ToPublicKey, diff --git a/src/descriptor/sh.rs b/src/descriptor/sh.rs index 74b123eeb..bd0c8c445 100644 --- a/src/descriptor/sh.rs +++ b/src/descriptor/sh.rs @@ -228,23 +228,25 @@ impl Sh { } } - /// Obtain the corresponding script pubkey for this descriptor - /// Non failing verion of [`DescriptorTrait::address`] for this descriptor - pub fn addr(&self, network: Network) -> Address { - match self.inner { - ShInner::Wsh(ref wsh) => { - Address::p2sh(&wsh.spk(), network).expect("Size checked in Miniscript") - } - ShInner::Wpkh(ref wpkh) => { - Address::p2sh(&wpkh.spk(), network).expect("Size checked in Miniscript") - } - ShInner::SortedMulti(ref smv) => { - Address::p2sh(&smv.encode(), network).expect("Size checked in Miniscript") - } - ShInner::Ms(ref ms) => { - Address::p2sh(&ms.encode(), network).expect("Size checked in Miniscript") - } - } + /// Obtains the corresponding address for this descriptor. + pub fn address(&self, network: Network) -> Address { + let addr = self.address_fallible(network); + + // Size is checked in `check_global_consensus_validity`. + assert!(addr.is_ok()); + addr.expect("only fails if size > MAX_SCRIPT_ELEMENT_SIZE") + } + + fn address_fallible(&self, network: Network) -> Result { + 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) } /// Obtain the underlying miniscript for this descriptor @@ -274,18 +276,6 @@ impl Sh { } impl DescriptorTrait for Sh { - fn address(&self, network: Network) -> Result - where - Pk: ToPublicKey, - { - match self.inner { - ShInner::Wsh(ref wsh) => Ok(Address::p2sh(&wsh.spk(), network)?), - ShInner::Wpkh(ref wpkh) => Ok(Address::p2sh(&wpkh.spk(), network)?), - ShInner::SortedMulti(ref smv) => Ok(Address::p2sh(&smv.encode(), network)?), - ShInner::Ms(ref ms) => Ok(Address::p2sh(&ms.encode(), network)?), - } - } - fn script_pubkey(&self) -> Script where Pk: ToPublicKey, diff --git a/src/descriptor/tr.rs b/src/descriptor/tr.rs index 51001f0ea..bfbbdd847 100644 --- a/src/descriptor/tr.rs +++ b/src/descriptor/tr.rs @@ -292,11 +292,10 @@ impl Tr { .into_script() } - /// Obtain the corresponding script pubkey for this descriptor - /// Same as[`DescriptorTrait::address`] for this descriptor - pub fn addr(&self, network: Network) -> Result { + /// Obtains the corresponding address for this descriptor. + pub fn address(&self, network: Network) -> Address { let spend_info = self.spend_info(); - Ok(Address::p2tr_tweaked(spend_info.output_key(), network)) + Address::p2tr_tweaked(spend_info.output_key(), network) } } @@ -556,13 +555,6 @@ impl Liftable for Tr { } impl DescriptorTrait for Tr { - fn address(&self, network: Network) -> Result - where - Pk: ToPublicKey, - { - self.addr(network) - } - fn script_pubkey(&self) -> Script where Pk: ToPublicKey, From e08f833614e45d45e5fb7f8de4e16765733466ad Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 17 May 2022 11:02:00 +1000 Subject: [PATCH 5/9] Remove script_pubkey from DescriptorTrait In preparation for removing the `DescriptorTrait` move the `script_pubkey` trait methods onto each individual descriptor. Replaces the `spk` method. Note that once upon a time `spk` was an infallible version of `script_pubkey` but now `script_pubkey` is itself infallible so this patch just renames the `spk` method and removes the trait method. --- examples/htlc.rs | 2 +- examples/parse.rs | 2 +- src/descriptor/bare.rs | 36 +++++++++++------------------------- src/descriptor/mod.rs | 32 ++++++++++++-------------------- src/descriptor/segwitv0.rs | 26 +++++--------------------- src/descriptor/sh.rs | 20 ++++++-------------- src/descriptor/tr.rs | 12 ++---------- src/psbt/mod.rs | 5 +++-- 8 files changed, 41 insertions(+), 94 deletions(-) diff --git a/examples/htlc.rs b/examples/htlc.rs index 3db169773..38c12a14f 100644 --- a/examples/htlc.rs +++ b/examples/htlc.rs @@ -53,7 +53,7 @@ fn main() { // Get the scriptPpubkey for this Wsh descriptor. assert_eq!( - format!("{:x}", htlc_descriptor.spk()), + format!("{:x}", htlc_descriptor.script_pubkey()), "0020d853877af928a8d2a569c9c0ed14bd16f6a80ce9cccaf8a6150fd8f7f8867ae2" ); diff --git a/examples/parse.rs b/examples/parse.rs index 3e1db2172..9884eed52 100644 --- a/examples/parse.rs +++ b/examples/parse.rs @@ -44,7 +44,7 @@ fn main() { // us to call infallible methods for getting script pubkey. if let Descriptor::Wsh(wsh) = &desc { assert_eq!( - format!("{:x}", wsh.spk()), + format!("{:x}", wsh.script_pubkey()), "0020daef16dd7c946a3e735a6e43310cb2ce33dfd14a04f76bf8241a16654cb2f0f9" ); } diff --git a/src/descriptor/bare.rs b/src/descriptor/bare.rs index e5a447cf0..7515de9f0 100644 --- a/src/descriptor/bare.rs +++ b/src/descriptor/bare.rs @@ -69,22 +69,21 @@ impl Bare { } impl Bare { - /// Obtain the corresponding script pubkey for this descriptor - /// Non failing verion of [`DescriptorTrait::script_pubkey`] for this descriptor - pub fn spk(&self) -> Script { + /// Obtains the corresponding script pubkey for this descriptor. + pub fn script_pubkey(&self) -> Script { self.ms.encode() } /// Obtain the underlying miniscript for this descriptor /// Non failing verion of [`DescriptorTrait::explicit_script`] for this descriptor pub fn inner_script(&self) -> Script { - self.spk() + self.script_pubkey() } /// Obtain the pre bip-340 signature script code for this descriptor /// Non failing verion of [`DescriptorTrait::script_code`] for this descriptor pub fn ecdsa_sighash_script_code(&self) -> Script { - self.spk() + self.script_pubkey() } } @@ -139,13 +138,6 @@ where } impl DescriptorTrait for Bare { - fn script_pubkey(&self) -> Script - where - Pk: ToPublicKey, - { - self.spk() - } - fn unsigned_script_sig(&self) -> Script where Pk: ToPublicKey, @@ -249,10 +241,11 @@ impl Pkh { } impl Pkh { - /// Obtain the corresponding script pubkey for this descriptor - /// Non failing verion of [`DescriptorTrait::script_pubkey`] for this descriptor - pub fn spk(&self) -> Script { - let addr = Address::p2pkh(&self.pk.to_public_key(), Network::Bitcoin); + /// Obtains the corresponding script pubkey for this descriptor. + pub fn script_pubkey(&self) -> Script { + // Fine to hard code the `Network` here because we immediately call + // `script_pubkey` which does not use the `network` field of `Address`. + let addr = self.address(Network::Bitcoin); addr.script_pubkey() } @@ -264,13 +257,13 @@ impl Pkh { /// Obtain the underlying miniscript for this descriptor /// Non failing verion of [`DescriptorTrait::explicit_script`] for this descriptor pub fn inner_script(&self) -> Script { - self.spk() + self.script_pubkey() } /// Obtain the pre bip-340 signature script code for this descriptor /// Non failing verion of [`DescriptorTrait::script_code`] for this descriptor pub fn ecdsa_sighash_script_code(&self) -> Script { - self.spk() + self.script_pubkey() } } @@ -333,13 +326,6 @@ where } impl DescriptorTrait for Pkh { - fn script_pubkey(&self) -> Script - where - Pk: ToPublicKey, - { - self.spk() - } - fn unsigned_script_sig(&self) -> Script where Pk: ToPublicKey, diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index 0794a11f2..a99dd476a 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -76,11 +76,6 @@ pub type KeyMap = HashMap; // because of traits cannot know underlying generic of Self. // Thus, we must implement additional trait for translate function pub trait DescriptorTrait { - /// Computes the scriptpubkey of the descriptor - fn script_pubkey(&self) -> Script - where - Pk: ToPublicKey; - /// Computes the scriptSig that will be in place for an unsigned /// input spending an output with this descriptor. For pre-segwit /// descriptors, which use the scriptSig for signatures, this @@ -416,6 +411,18 @@ impl Descriptor { Descriptor::Tr(ref tr) => Ok(tr.address(network)), } } + + /// Computes the scriptpubkey of the descriptor. + pub fn script_pubkey(&self) -> Script { + match *self { + Descriptor::Bare(ref bare) => bare.script_pubkey(), + Descriptor::Pkh(ref pkh) => pkh.script_pubkey(), + Descriptor::Wpkh(ref wpkh) => wpkh.script_pubkey(), + Descriptor::Wsh(ref wsh) => wsh.script_pubkey(), + Descriptor::Sh(ref sh) => sh.script_pubkey(), + Descriptor::Tr(ref tr) => tr.script_pubkey(), + } + } } impl TranslatePk for Descriptor

@@ -449,21 +456,6 @@ where } impl DescriptorTrait for Descriptor { - /// Computes the scriptpubkey of the descriptor - fn script_pubkey(&self) -> Script - where - Pk: ToPublicKey, - { - match *self { - Descriptor::Bare(ref bare) => bare.script_pubkey(), - Descriptor::Pkh(ref pkh) => pkh.script_pubkey(), - Descriptor::Wpkh(ref wpkh) => wpkh.script_pubkey(), - Descriptor::Wsh(ref wsh) => wsh.script_pubkey(), - Descriptor::Sh(ref sh) => sh.script_pubkey(), - Descriptor::Tr(ref tr) => tr.script_pubkey(), - } - } - /// Computes the scriptSig that will be in place for an unsigned /// input spending an output with this descriptor. For pre-segwit /// descriptors, which use the scriptSig for signatures, this diff --git a/src/descriptor/segwitv0.rs b/src/descriptor/segwitv0.rs index 5103b4aa6..f0f5f9e61 100644 --- a/src/descriptor/segwitv0.rs +++ b/src/descriptor/segwitv0.rs @@ -86,9 +86,8 @@ impl Wsh { } impl Wsh { - /// Obtain the corresponding script pubkey for this descriptor - /// Non failing verion of [`DescriptorTrait::script_pubkey`] for this descriptor - pub fn spk(&self) -> Script { + /// Obtains the corresponding script pubkey for this descriptor. + pub fn script_pubkey(&self) -> Script { self.inner_script().to_v0_p2wsh() } @@ -197,13 +196,6 @@ where } impl DescriptorTrait for Wsh { - fn script_pubkey(&self) -> Script - where - Pk: ToPublicKey, - { - self.spk() - } - fn unsigned_script_sig(&self) -> Script where Pk: ToPublicKey, @@ -356,9 +348,8 @@ impl Wpkh { } impl Wpkh { - /// Obtain the corresponding script pubkey for this descriptor - /// Non failing verion of [`DescriptorTrait::script_pubkey`] for this descriptor - pub fn spk(&self) -> Script { + /// Obtains the corresponding script pubkey for this descriptor. + pub fn script_pubkey(&self) -> Script { let addr = Address::p2wpkh(&self.pk.to_public_key(), Network::Bitcoin) .expect("wpkh descriptors have compressed keys"); addr.script_pubkey() @@ -373,7 +364,7 @@ impl Wpkh { /// Obtain the underlying miniscript for this descriptor /// Non failing verion of [`DescriptorTrait::explicit_script`] for this descriptor pub fn inner_script(&self) -> Script { - self.spk() + self.script_pubkey() } /// Obtain the pre bip-340 signature script code for this descriptor @@ -447,13 +438,6 @@ where } impl DescriptorTrait for Wpkh { - fn script_pubkey(&self) -> Script - where - Pk: ToPublicKey, - { - self.spk() - } - fn unsigned_script_sig(&self) -> Script where Pk: ToPublicKey, diff --git a/src/descriptor/sh.rs b/src/descriptor/sh.rs index bd0c8c445..0dfe2530d 100644 --- a/src/descriptor/sh.rs +++ b/src/descriptor/sh.rs @@ -217,12 +217,11 @@ impl Sh { } impl Sh { - /// Obtain the corresponding script pubkey for this descriptor - /// Non failing verion of [`DescriptorTrait::script_pubkey`] for this descriptor - pub fn spk(&self) -> Script { + /// Obtains the corresponding script pubkey for this descriptor. + pub fn script_pubkey(&self) -> Script { match self.inner { - ShInner::Wsh(ref wsh) => wsh.spk().to_p2sh(), - ShInner::Wpkh(ref wpkh) => wpkh.spk().to_p2sh(), + 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(), } @@ -254,7 +253,7 @@ impl Sh { pub fn inner_script(&self) -> Script { match self.inner { ShInner::Wsh(ref wsh) => wsh.inner_script(), - ShInner::Wpkh(ref wpkh) => wpkh.spk(), + ShInner::Wpkh(ref wpkh) => wpkh.script_pubkey(), ShInner::SortedMulti(ref smv) => smv.encode(), ShInner::Ms(ref ms) => ms.encode(), } @@ -276,13 +275,6 @@ impl Sh { } impl DescriptorTrait for Sh { - fn script_pubkey(&self) -> Script - where - Pk: ToPublicKey, - { - self.spk() - } - fn unsigned_script_sig(&self) -> Script where Pk: ToPublicKey, @@ -296,7 +288,7 @@ impl DescriptorTrait for Sh { .into_script() } ShInner::Wpkh(ref wpkh) => { - let redeem_script = wpkh.spk(); + let redeem_script = wpkh.script_pubkey(); script::Builder::new() .push_slice(&redeem_script[..]) .into_script() diff --git a/src/descriptor/tr.rs b/src/descriptor/tr.rs index bfbbdd847..29d12c07f 100644 --- a/src/descriptor/tr.rs +++ b/src/descriptor/tr.rs @@ -281,9 +281,8 @@ impl Tr { } impl Tr { - /// Obtain the corresponding script pubkey for this descriptor - /// Same as[`DescriptorTrait::script_pubkey`] for this descriptor - pub fn spk(&self) -> Script { + /// Obtains the corresponding script pubkey for this descriptor. + pub fn script_pubkey(&self) -> Script { let output_key = self.spend_info().output_key(); let builder = bitcoin::blockdata::script::Builder::new(); builder @@ -555,13 +554,6 @@ impl Liftable for Tr { } impl DescriptorTrait for Tr { - fn script_pubkey(&self) -> Script - where - Pk: ToPublicKey, - { - self.spk() - } - fn unsigned_script_sig(&self) -> Script where Pk: ToPublicKey, diff --git a/src/psbt/mod.rs b/src/psbt/mod.rs index 9c23bdf0e..66efb2738 100644 --- a/src/psbt/mod.rs +++ b/src/psbt/mod.rs @@ -34,8 +34,8 @@ use crate::miniscript::iter::PkPkh; use crate::miniscript::limits::SEQUENCE_LOCKTIME_DISABLE_FLAG; use crate::miniscript::satisfy::{After, Older}; use crate::{ - descriptor, interpreter, Descriptor, DescriptorPublicKey, DescriptorTrait, MiniscriptKey, - Preimage32, Satisfier, ToPublicKey, TranslatePk, TranslatePk2, + descriptor, interpreter, Descriptor, DescriptorPublicKey, MiniscriptKey, Preimage32, Satisfier, + ToPublicKey, TranslatePk, TranslatePk2, }; mod finalizer; @@ -1152,6 +1152,7 @@ mod tests { use bitcoin::{OutPoint, TxIn, TxOut, XOnlyPublicKey}; use super::*; + use crate::descriptor::DescriptorTrait; use crate::Miniscript; #[test] From 67d7c0e3dc492a3de476522f676235fe201d3943 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 17 May 2022 11:11:51 +1000 Subject: [PATCH 6/9] Remove unsigned_script_sig from DescriptorTrait In preparation for removing the `DescriptorTrait` move the `unsigned_script_sig` trait methods onto each individual descriptor as required (`Sh` only). All the other trait method implementations just return `Script::new()`, just call `new` directly from the implantation of `unsigned_script_sig` on `Descriptor`. --- src/descriptor/bare.rs | 14 ---------- src/descriptor/mod.rs | 52 +++++++++++++------------------------- src/descriptor/segwitv0.rs | 14 ---------- src/descriptor/sh.rs | 16 +++++++----- src/descriptor/tr.rs | 7 ----- 5 files changed, 28 insertions(+), 75 deletions(-) diff --git a/src/descriptor/bare.rs b/src/descriptor/bare.rs index 7515de9f0..63447de6c 100644 --- a/src/descriptor/bare.rs +++ b/src/descriptor/bare.rs @@ -138,13 +138,6 @@ where } impl DescriptorTrait for Bare { - fn unsigned_script_sig(&self) -> Script - where - Pk: ToPublicKey, - { - Script::new() - } - fn explicit_script(&self) -> Result where Pk: ToPublicKey, @@ -326,13 +319,6 @@ where } impl DescriptorTrait for Pkh { - fn unsigned_script_sig(&self) -> Script - where - Pk: ToPublicKey, - { - Script::new() - } - fn explicit_script(&self) -> Result where Pk: ToPublicKey, diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index a99dd476a..40d8e4081 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -76,18 +76,6 @@ pub type KeyMap = HashMap; // because of traits cannot know underlying generic of Self. // Thus, we must implement additional trait for translate function pub trait DescriptorTrait { - /// Computes the scriptSig that will be in place for an unsigned - /// input spending an output with this descriptor. For pre-segwit - /// descriptors, which use the scriptSig for signatures, this - /// returns the empty script. - /// - /// This is used in Segwit transactions to produce an unsigned - /// transaction whose txid will not change during signing (since - /// only the witness data will change). - fn unsigned_script_sig(&self) -> Script - where - Pk: ToPublicKey; - /// Computes the "witness script" of the descriptor, i.e. the underlying /// script before any hashing is done. For `Bare`, `Pkh` and `Wpkh` this /// is the scriptPubkey; for `ShWpkh` and `Sh` this is the redeemScript; @@ -423,6 +411,24 @@ impl Descriptor { Descriptor::Tr(ref tr) => tr.script_pubkey(), } } + + /// Computes the scriptSig that will be in place for an unsigned input + /// spending an output with this descriptor. For pre-segwit descriptors, + /// which use the scriptSig for signatures, this returns the empty script. + /// + /// This is used in Segwit transactions to produce an unsigned transaction + /// whose txid will not change during signing (since only the witness data + /// will change). + pub fn unsigned_script_sig(&self) -> Script { + match *self { + Descriptor::Bare(_) => Script::new(), + Descriptor::Pkh(_) => Script::new(), + Descriptor::Wpkh(_) => Script::new(), + Descriptor::Wsh(_) => Script::new(), + Descriptor::Sh(ref sh) => sh.unsigned_script_sig(), + Descriptor::Tr(_) => Script::new(), + } + } } impl TranslatePk for Descriptor

@@ -456,28 +462,6 @@ where } impl DescriptorTrait for Descriptor { - /// Computes the scriptSig that will be in place for an unsigned - /// input spending an output with this descriptor. For pre-segwit - /// descriptors, which use the scriptSig for signatures, this - /// returns the empty script. - /// - /// This is used in Segwit transactions to produce an unsigned - /// transaction whose txid will not change during signing (since - /// only the witness data will change). - fn unsigned_script_sig(&self) -> Script - where - Pk: ToPublicKey, - { - match *self { - Descriptor::Bare(ref bare) => bare.unsigned_script_sig(), - Descriptor::Pkh(ref pkh) => pkh.unsigned_script_sig(), - Descriptor::Wpkh(ref wpkh) => wpkh.unsigned_script_sig(), - Descriptor::Wsh(ref wsh) => wsh.unsigned_script_sig(), - Descriptor::Sh(ref sh) => sh.unsigned_script_sig(), - Descriptor::Tr(ref tr) => tr.unsigned_script_sig(), - } - } - /// Computes the "witness script" of the descriptor, i.e. the underlying /// script before any hashing is done. For `Bare`, `Pkh` and `Wpkh` this /// is the scriptPubkey; for `ShWpkh` and `Sh` this is the redeemScript; diff --git a/src/descriptor/segwitv0.rs b/src/descriptor/segwitv0.rs index f0f5f9e61..44ac7de1a 100644 --- a/src/descriptor/segwitv0.rs +++ b/src/descriptor/segwitv0.rs @@ -196,13 +196,6 @@ where } impl DescriptorTrait for Wsh { - fn unsigned_script_sig(&self) -> Script - where - Pk: ToPublicKey, - { - Script::new() - } - fn explicit_script(&self) -> Result where Pk: ToPublicKey, @@ -438,13 +431,6 @@ where } impl DescriptorTrait for Wpkh { - fn unsigned_script_sig(&self) -> Script - where - Pk: ToPublicKey, - { - Script::new() - } - fn explicit_script(&self) -> Result where Pk: ToPublicKey, diff --git a/src/descriptor/sh.rs b/src/descriptor/sh.rs index 0dfe2530d..d2742d1f2 100644 --- a/src/descriptor/sh.rs +++ b/src/descriptor/sh.rs @@ -272,13 +272,15 @@ impl Sh { ShInner::Ms(ref ms) => ms.encode(), } } -} -impl DescriptorTrait for Sh { - fn unsigned_script_sig(&self) -> Script - where - Pk: ToPublicKey, - { + /// Computes the scriptSig that will be in place for an unsigned input + /// spending an output with this descriptor. For pre-segwit descriptors, + /// which use the scriptSig for signatures, this returns the empty script. + /// + /// This is used in Segwit transactions to produce an unsigned transaction + /// whose txid will not change during signing (since only the witness data + /// will change). + pub fn unsigned_script_sig(&self) -> Script { match self.inner { ShInner::Wsh(ref wsh) => { // wsh explicit must contain exactly 1 element @@ -296,7 +298,9 @@ impl DescriptorTrait for Sh { ShInner::SortedMulti(..) | ShInner::Ms(..) => Script::new(), } } +} +impl DescriptorTrait for Sh { fn explicit_script(&self) -> Result where Pk: ToPublicKey, diff --git a/src/descriptor/tr.rs b/src/descriptor/tr.rs index 29d12c07f..a3565f290 100644 --- a/src/descriptor/tr.rs +++ b/src/descriptor/tr.rs @@ -554,13 +554,6 @@ impl Liftable for Tr { } impl DescriptorTrait for Tr { - fn unsigned_script_sig(&self) -> Script - where - Pk: ToPublicKey, - { - Script::new() - } - fn explicit_script(&self) -> Result where Pk: ToPublicKey, From c6884fce02b481f54555a7136e231d567ce955eb Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 17 May 2022 11:20:37 +1000 Subject: [PATCH 7/9] Remove explicit_script from DescriptorTrait In preparation for removing the `DescriptorTrait` remove the `explicit_script` trait method. Implement the same logic on `Descriptor` directly but call through to `inner_script` or `script_pubkey` for each descriptor as required. --- examples/parse.rs | 2 +- src/descriptor/bare.rs | 16 ------------- src/descriptor/mod.rs | 46 ++++++++++++++------------------------ src/descriptor/segwitv0.rs | 16 ------------- src/descriptor/sh.rs | 8 ------- src/descriptor/tr.rs | 7 ------ src/psbt/mod.rs | 1 - 7 files changed, 18 insertions(+), 78 deletions(-) diff --git a/examples/parse.rs b/examples/parse.rs index 9884eed52..9bd00ff8c 100644 --- a/examples/parse.rs +++ b/examples/parse.rs @@ -17,7 +17,7 @@ use std::str::FromStr; use miniscript::descriptor::DescriptorType; -use miniscript::{Descriptor, DescriptorTrait}; +use miniscript::Descriptor; fn main() { let desc = miniscript::Descriptor::::from_str( diff --git a/src/descriptor/bare.rs b/src/descriptor/bare.rs index 63447de6c..3ab4f18fa 100644 --- a/src/descriptor/bare.rs +++ b/src/descriptor/bare.rs @@ -75,7 +75,6 @@ impl Bare { } /// Obtain the underlying miniscript for this descriptor - /// Non failing verion of [`DescriptorTrait::explicit_script`] for this descriptor pub fn inner_script(&self) -> Script { self.script_pubkey() } @@ -138,13 +137,6 @@ where } impl DescriptorTrait for Bare { - fn explicit_script(&self) -> Result - where - Pk: ToPublicKey, - { - Ok(self.inner_script()) - } - fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, Script), Error> where Pk: ToPublicKey, @@ -248,7 +240,6 @@ impl Pkh { } /// Obtain the underlying miniscript for this descriptor - /// Non failing verion of [`DescriptorTrait::explicit_script`] for this descriptor pub fn inner_script(&self) -> Script { self.script_pubkey() } @@ -319,13 +310,6 @@ where } impl DescriptorTrait for Pkh { - fn explicit_script(&self) -> Result - where - Pk: ToPublicKey, - { - Ok(self.inner_script()) - } - fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, Script), Error> where Pk: ToPublicKey, diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index 40d8e4081..be0f6cc0b 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -76,15 +76,6 @@ pub type KeyMap = HashMap; // because of traits cannot know underlying generic of Self. // Thus, we must implement additional trait for translate function pub trait DescriptorTrait { - /// Computes the "witness script" of the descriptor, i.e. the underlying - /// script before any hashing is done. For `Bare`, `Pkh` and `Wpkh` this - /// is the scriptPubkey; for `ShWpkh` and `Sh` this is the redeemScript; - /// for the others it is the witness script. - /// For `Tr` descriptors, this will error as there is no underlying script - fn explicit_script(&self) -> Result - where - Pk: ToPublicKey; - /// Returns satisfying non-malleable witness and scriptSig with minimum weight to spend an /// output controlled by the given descriptor if it possible to /// construct one using the satisfier S. @@ -429,6 +420,23 @@ impl Descriptor { Descriptor::Tr(_) => Script::new(), } } + + /// Computes the the underlying script before any hashing is done. For + /// `Bare`, `Pkh` and `Wpkh` this is the scriptPubkey; for `ShWpkh` and `Sh` + /// this is the redeemScript; for the others it is the witness script. + /// + /// # Errors + /// If the descriptor is a taproot descriptor. + pub fn explicit_script(&self) -> Result { + match *self { + Descriptor::Bare(ref bare) => Ok(bare.script_pubkey()), + Descriptor::Pkh(ref pkh) => Ok(pkh.script_pubkey()), + Descriptor::Wpkh(ref wpkh) => Ok(wpkh.script_pubkey()), + Descriptor::Wsh(ref wsh) => Ok(wsh.inner_script()), + Descriptor::Sh(ref sh) => Ok(sh.inner_script()), + Descriptor::Tr(_) => Err(Error::TrNoScriptCode), + } + } } impl TranslatePk for Descriptor

@@ -462,26 +470,6 @@ where } impl DescriptorTrait for Descriptor { - /// Computes the "witness script" of the descriptor, i.e. the underlying - /// script before any hashing is done. For `Bare`, `Pkh` and `Wpkh` this - /// is the scriptPubkey; for `ShWpkh` and `Sh` this is the redeemScript; - /// for the others it is the witness script. - /// Errors: - /// - When the descriptor is Tr - fn explicit_script(&self) -> Result - where - Pk: ToPublicKey, - { - match *self { - Descriptor::Bare(ref bare) => bare.explicit_script(), - Descriptor::Pkh(ref pkh) => pkh.explicit_script(), - Descriptor::Wpkh(ref wpkh) => wpkh.explicit_script(), - Descriptor::Wsh(ref wsh) => wsh.explicit_script(), - Descriptor::Sh(ref sh) => sh.explicit_script(), - Descriptor::Tr(ref tr) => tr.explicit_script(), - } - } - /// Returns satisfying non-malleable witness and scriptSig to spend an /// output controlled by the given descriptor if it possible to /// construct one using the satisfier S. diff --git a/src/descriptor/segwitv0.rs b/src/descriptor/segwitv0.rs index 44ac7de1a..8adb42e08 100644 --- a/src/descriptor/segwitv0.rs +++ b/src/descriptor/segwitv0.rs @@ -100,7 +100,6 @@ impl Wsh { } /// Obtain the underlying miniscript for this descriptor - /// Non failing verion of [`DescriptorTrait::explicit_script`] for this descriptor pub fn inner_script(&self) -> Script { match self.inner { WshInner::SortedMulti(ref smv) => smv.encode(), @@ -196,13 +195,6 @@ where } impl DescriptorTrait for Wsh { - fn explicit_script(&self) -> Result - where - Pk: ToPublicKey, - { - Ok(self.inner_script()) - } - fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, Script), Error> where Pk: ToPublicKey, @@ -355,7 +347,6 @@ impl Wpkh { } /// Obtain the underlying miniscript for this descriptor - /// Non failing verion of [`DescriptorTrait::explicit_script`] for this descriptor pub fn inner_script(&self) -> Script { self.script_pubkey() } @@ -431,13 +422,6 @@ where } impl DescriptorTrait for Wpkh { - fn explicit_script(&self) -> Result - where - Pk: ToPublicKey, - { - Ok(self.inner_script()) - } - fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, Script), Error> where Pk: ToPublicKey, diff --git a/src/descriptor/sh.rs b/src/descriptor/sh.rs index d2742d1f2..de0258f10 100644 --- a/src/descriptor/sh.rs +++ b/src/descriptor/sh.rs @@ -249,7 +249,6 @@ impl Sh { } /// Obtain the underlying miniscript for this descriptor - /// Non failing verion of [`DescriptorTrait::explicit_script`] for this descriptor pub fn inner_script(&self) -> Script { match self.inner { ShInner::Wsh(ref wsh) => wsh.inner_script(), @@ -301,13 +300,6 @@ impl Sh { } impl DescriptorTrait for Sh { - fn explicit_script(&self) -> Result - where - Pk: ToPublicKey, - { - Ok(self.inner_script()) - } - fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, Script), Error> where Pk: ToPublicKey, diff --git a/src/descriptor/tr.rs b/src/descriptor/tr.rs index a3565f290..1b4d32f82 100644 --- a/src/descriptor/tr.rs +++ b/src/descriptor/tr.rs @@ -554,13 +554,6 @@ impl Liftable for Tr { } impl DescriptorTrait for Tr { - fn explicit_script(&self) -> Result - where - Pk: ToPublicKey, - { - Err(Error::TrNoScriptCode) - } - fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, Script), Error> where Pk: ToPublicKey, diff --git a/src/psbt/mod.rs b/src/psbt/mod.rs index 66efb2738..33df897ad 100644 --- a/src/psbt/mod.rs +++ b/src/psbt/mod.rs @@ -1152,7 +1152,6 @@ mod tests { use bitcoin::{OutPoint, TxIn, TxOut, XOnlyPublicKey}; use super::*; - use crate::descriptor::DescriptorTrait; use crate::Miniscript; #[test] From 52a480d9a656fa0d6b61f92bc29aec64c1b4406c Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 17 May 2022 11:26:29 +1000 Subject: [PATCH 8/9] Remove script_code from DescriptorTrait In preparation for removing the `DescriptorTrait` move the `script_code` trait methods onto each individual descriptor. Fix docs on related methods also (e.g. `inner_scipt`). Implement `script_code` directly on `Descriptor`. --- src/descriptor/bare.rs | 24 ++++--------------- src/descriptor/mod.rs | 47 +++++++++++++++----------------------- src/descriptor/segwitv0.rs | 24 ++++--------------- src/descriptor/sh.rs | 10 +------- src/descriptor/tr.rs | 7 ------ 5 files changed, 27 insertions(+), 85 deletions(-) diff --git a/src/descriptor/bare.rs b/src/descriptor/bare.rs index 3ab4f18fa..a78c32bf4 100644 --- a/src/descriptor/bare.rs +++ b/src/descriptor/bare.rs @@ -74,13 +74,12 @@ impl Bare { self.ms.encode() } - /// Obtain the underlying miniscript for this descriptor + /// Obtains the underlying miniscript for this descriptor. pub fn inner_script(&self) -> Script { self.script_pubkey() } - /// Obtain the pre bip-340 signature script code for this descriptor - /// Non failing verion of [`DescriptorTrait::script_code`] for this descriptor + /// Obtains the pre bip-340 signature script code for this descriptor. pub fn ecdsa_sighash_script_code(&self) -> Script { self.script_pubkey() } @@ -163,13 +162,6 @@ impl DescriptorTrait for Bare { let scriptsig_len = self.ms.max_satisfaction_size()?; Ok(4 * (varint_len(scriptsig_len) + scriptsig_len)) } - - fn script_code(&self) -> Result - where - Pk: ToPublicKey, - { - Ok(self.ecdsa_sighash_script_code()) - } } impl ForEachKey for Bare { @@ -239,13 +231,12 @@ impl Pkh { Address::p2pkh(&self.pk.to_public_key(), network) } - /// Obtain the underlying miniscript for this descriptor + /// Obtains the underlying miniscript for this descriptor. pub fn inner_script(&self) -> Script { self.script_pubkey() } - /// Obtain the pre bip-340 signature script code for this descriptor - /// Non failing verion of [`DescriptorTrait::script_code`] for this descriptor + /// Obtains the pre bip-340 signature script code for this descriptor. pub fn ecdsa_sighash_script_code(&self) -> Script { self.script_pubkey() } @@ -339,13 +330,6 @@ impl DescriptorTrait for Pkh { fn max_satisfaction_weight(&self) -> Result { Ok(4 * (1 + 73 + BareCtx::pk_len(&self.pk))) } - - fn script_code(&self) -> Result - where - Pk: ToPublicKey, - { - Ok(self.ecdsa_sighash_script_code()) - } } impl ForEachKey for Pkh { diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index be0f6cc0b..647546fb2 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -113,16 +113,6 @@ pub trait DescriptorTrait { /// scriptSig and witness stack length. /// Returns Error when the descriptor is impossible to safisfy (ex: sh(OP_FALSE)) fn max_satisfaction_weight(&self) -> Result; - - /// Get the `scriptCode` of a transaction output. - /// - /// The `scriptCode` is the Script of the previous transaction output being serialized in the - /// sighash when evaluating a `CHECKSIG` & co. OP code. - /// Errors: - /// - When the descriptor is Tr - fn script_code(&self) -> Result - where - Pk: ToPublicKey; } /// Script descriptor @@ -437,6 +427,24 @@ impl Descriptor { Descriptor::Tr(_) => Err(Error::TrNoScriptCode), } } + + /// Computes the `scriptCode` of a transaction output. + /// + /// The `scriptCode` is the Script of the previous transaction output being + /// serialized in the sighash when evaluating a `CHECKSIG` & co. OP code. + /// + /// # Errors + /// If the descriptor is a taproot descriptor. + pub fn script_code(&self) -> Result { + match *self { + Descriptor::Bare(ref bare) => Ok(bare.ecdsa_sighash_script_code()), + Descriptor::Pkh(ref pkh) => Ok(pkh.ecdsa_sighash_script_code()), + Descriptor::Wpkh(ref wpkh) => Ok(wpkh.ecdsa_sighash_script_code()), + Descriptor::Wsh(ref wsh) => Ok(wsh.ecdsa_sighash_script_code()), + Descriptor::Sh(ref sh) => Ok(sh.ecdsa_sighash_script_code()), + Descriptor::Tr(_) => Err(Error::TrNoScriptCode), + } + } } impl TranslatePk for Descriptor

@@ -520,25 +528,6 @@ impl DescriptorTrait for Descriptor { Descriptor::Tr(ref tr) => tr.max_satisfaction_weight(), } } - - /// Get the `scriptCode` of a transaction output. - /// - /// The `scriptCode` is the Script of the previous transaction output being serialized in the - /// sighash when evaluating a `CHECKSIG` & co. OP code. - /// Returns Error for Tr descriptors - fn script_code(&self) -> Result - where - Pk: ToPublicKey, - { - match *self { - Descriptor::Bare(ref bare) => bare.script_code(), - Descriptor::Pkh(ref pkh) => pkh.script_code(), - Descriptor::Wpkh(ref wpkh) => wpkh.script_code(), - Descriptor::Wsh(ref wsh) => wsh.script_code(), - Descriptor::Sh(ref sh) => sh.script_code(), - Descriptor::Tr(ref tr) => tr.script_code(), - } - } } impl ForEachKey for Descriptor { diff --git a/src/descriptor/segwitv0.rs b/src/descriptor/segwitv0.rs index 8adb42e08..dc1ee6778 100644 --- a/src/descriptor/segwitv0.rs +++ b/src/descriptor/segwitv0.rs @@ -99,7 +99,7 @@ impl Wsh { } } - /// Obtain the underlying miniscript for this descriptor + /// Obtains the underlying miniscript for this descriptor. pub fn inner_script(&self) -> Script { match self.inner { WshInner::SortedMulti(ref smv) => smv.encode(), @@ -107,8 +107,7 @@ impl Wsh { } } - /// Obtain the pre bip-340 signature script code for this descriptor - /// Non failing verion of [`DescriptorTrait::script_code`] for this descriptor + /// Obtains the pre bip-340 signature script code for this descriptor. pub fn ecdsa_sighash_script_code(&self) -> Script { self.inner_script() } @@ -243,13 +242,6 @@ impl DescriptorTrait for Wsh { varint_len(max_sat_elems) + max_sat_size) } - - fn script_code(&self) -> Result - where - Pk: ToPublicKey, - { - Ok(self.ecdsa_sighash_script_code()) - } } impl ForEachKey for Wsh { @@ -346,13 +338,12 @@ impl Wpkh { .expect("Rust Miniscript types don't allow uncompressed pks in segwit descriptors") } - /// Obtain the underlying miniscript for this descriptor + /// Obtains the underlying miniscript for this descriptor. pub fn inner_script(&self) -> Script { self.script_pubkey() } - /// Obtain the pre bip-340 signature script code for this descriptor - /// Non failing verion of [`DescriptorTrait::script_code`] for this descriptor + /// Obtains the pre bip-340 signature script code for this descriptor. pub fn ecdsa_sighash_script_code(&self) -> Script { // For SegWit outputs, it is defined by bip-0143 (quoted below) and is different from // the previous txo's scriptPubKey. @@ -448,13 +439,6 @@ impl DescriptorTrait for Wpkh { fn max_satisfaction_weight(&self) -> Result { Ok(4 + 1 + 73 + Segwitv0::pk_len(&self.pk)) } - - fn script_code(&self) -> Result - where - Pk: ToPublicKey, - { - Ok(self.ecdsa_sighash_script_code()) - } } impl ForEachKey for Wpkh { diff --git a/src/descriptor/sh.rs b/src/descriptor/sh.rs index de0258f10..4d666a5aa 100644 --- a/src/descriptor/sh.rs +++ b/src/descriptor/sh.rs @@ -258,8 +258,7 @@ impl Sh { } } - /// Obtain the pre bip-340 signature script code for this descriptor - /// Non failing verion of [`DescriptorTrait::script_code`] for this descriptor + /// Obtains the pre bip-340 signature script code for this descriptor. pub fn ecdsa_sighash_script_code(&self) -> Script { match self.inner { // - For P2WSH witness program, if the witnessScript does not contain any `OP_CODESEPARATOR`, @@ -374,13 +373,6 @@ impl DescriptorTrait for Sh { } }) } - - fn script_code(&self) -> Result - where - Pk: ToPublicKey, - { - Ok(self.ecdsa_sighash_script_code()) - } } impl ForEachKey for Sh { diff --git a/src/descriptor/tr.rs b/src/descriptor/tr.rs index 1b4d32f82..7f2c49169 100644 --- a/src/descriptor/tr.rs +++ b/src/descriptor/tr.rs @@ -593,13 +593,6 @@ impl DescriptorTrait for Tr { } max_wieght.ok_or(Error::ImpossibleSatisfaction) } - - fn script_code(&self) -> Result - where - Pk: ToPublicKey, - { - Err(Error::TrNoScriptCode) - } } impl ForEachKey for Tr { From 32a74af28a223f3a84b8ac35c6ed50b0bd498b9a Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 17 May 2022 11:48:37 +1000 Subject: [PATCH 9/9] Delete the DescriptorTrait We never abstract over the `DescriptorTrait`, it is therefore questionable for it to exist. We have recently removed a number of trait methods out of the trait and implemented them directly on the respective descriptors. We can now do the same with the remaining 'satisfaction' trait methods. Implement the various satisfaction methods on each descriptor as required. Implement the methods directly on `Descriptor`. Delete the `DescriptorTrait`. --- examples/sign_multisig.rs | 1 - integration_test/src/test_cpp.rs | 2 +- integration_test/src/test_desc.rs | 4 +- src/descriptor/bare.rs | 142 +++++++++++++---------- src/descriptor/mod.rs | 151 ++++++++++--------------- src/descriptor/segwitv0.rs | 181 +++++++++++++++++------------- src/descriptor/sh.rs | 67 ++++++----- src/descriptor/tr.rs | 98 ++++++++-------- src/lib.rs | 5 +- src/psbt/finalizer.rs | 1 - 10 files changed, 338 insertions(+), 314 deletions(-) diff --git a/examples/sign_multisig.rs b/examples/sign_multisig.rs index 1ad82034e..5c58bf5d2 100644 --- a/examples/sign_multisig.rs +++ b/examples/sign_multisig.rs @@ -19,7 +19,6 @@ use std::str::FromStr; use bitcoin::blockdata::witness::Witness; use bitcoin::secp256k1; -use miniscript::DescriptorTrait; fn main() { let mut tx = spending_transaction(); diff --git a/integration_test/src/test_cpp.rs b/integration_test/src/test_cpp.rs index fec467019..2e6e8ab46 100644 --- a/integration_test/src/test_cpp.rs +++ b/integration_test/src/test_cpp.rs @@ -13,7 +13,7 @@ use miniscript::miniscript::iter; use miniscript::psbt::PsbtExt; use miniscript::MiniscriptKey; use miniscript::Segwitv0; -use miniscript::{Descriptor, DescriptorTrait, Miniscript}; +use miniscript::{Descriptor, Miniscript}; use std::collections::BTreeMap; use std::fs::File; use std::io::{self, BufRead}; diff --git a/integration_test/src/test_desc.rs b/integration_test/src/test_desc.rs index 8a6e1811d..9d4d0e7d6 100644 --- a/integration_test/src/test_desc.rs +++ b/integration_test/src/test_desc.rs @@ -13,8 +13,8 @@ use bitcoin::util::{psbt, sighash}; use bitcoin::{self, Amount, OutPoint, SchnorrSig, Script, Transaction, TxIn, TxOut, Txid}; use bitcoincore_rpc::{json, Client, RpcApi}; use miniscript::miniscript::iter; -use miniscript::psbt::{PsbtInputExt, PsbtExt}; -use miniscript::{Descriptor, DescriptorTrait, Miniscript, ToPublicKey}; +use miniscript::psbt::{PsbtExt, PsbtInputExt}; +use miniscript::{Descriptor, Miniscript, ToPublicKey}; use miniscript::{MiniscriptKey, ScriptContext}; use std::collections::BTreeMap; diff --git a/src/descriptor/bare.rs b/src/descriptor/bare.rs index a78c32bf4..269317d9c 100644 --- a/src/descriptor/bare.rs +++ b/src/descriptor/bare.rs @@ -25,7 +25,6 @@ use bitcoin::blockdata::script; use bitcoin::{Address, Network, Script}; use super::checksum::{desc_checksum, verify_checksum}; -use super::DescriptorTrait; use crate::expression::{self, FromTree}; use crate::miniscript::context::ScriptContext; use crate::policy::{semantic, Liftable}; @@ -66,6 +65,20 @@ impl Bare { self.ms.sanity_check()?; Ok(()) } + + /// Computes an upper bound on the weight of a satisfying witness to the + /// transaction. + /// + /// Assumes all ec-signatures are 73 bytes, including push opcode and + /// sighash suffix. Includes the weight of the VarInts encoding the + /// scriptSig and witness stack length. + /// + /// # Errors + /// When the descriptor is impossible to safisfy (ex: sh(OP_FALSE)). + pub fn max_satisfaction_weight(&self) -> Result { + let scriptsig_len = self.ms.max_satisfaction_size()?; + Ok(4 * (varint_len(scriptsig_len) + scriptsig_len)) + } } impl Bare { @@ -83,6 +96,32 @@ impl Bare { pub fn ecdsa_sighash_script_code(&self) -> Script { self.script_pubkey() } + + /// Returns satisfying non-malleable witness and scriptSig with minimum + /// weight to spend an output controlled by the given descriptor if it is + /// possible to construct one using the `satisfier`. + pub fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, Script), Error> + where + S: Satisfier, + { + let ms = self.ms.satisfy(satisfier)?; + let script_sig = witness_to_scriptsig(&ms); + let witness = vec![]; + Ok((witness, script_sig)) + } + + /// Returns satisfying, possibly malleable, witness and scriptSig with + /// minimum weight to spend an output controlled by the given descriptor if + /// it is possible to construct one using the `satisfier`. + pub fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, Script), Error> + where + S: Satisfier, + { + let ms = self.ms.satisfy_malleable(satisfier)?; + let script_sig = witness_to_scriptsig(&ms); + let witness = vec![]; + Ok((witness, script_sig)) + } } impl fmt::Debug for Bare { @@ -135,35 +174,6 @@ where } } -impl DescriptorTrait for Bare { - fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, Script), Error> - where - Pk: ToPublicKey, - S: Satisfier, - { - let ms = self.ms.satisfy(satisfier)?; - let script_sig = witness_to_scriptsig(&ms); - let witness = vec![]; - Ok((witness, script_sig)) - } - - fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, Script), Error> - where - Pk: ToPublicKey, - S: Satisfier, - { - let ms = self.ms.satisfy_malleable(satisfier)?; - let script_sig = witness_to_scriptsig(&ms); - let witness = vec![]; - Ok((witness, script_sig)) - } - - fn max_satisfaction_weight(&self) -> Result { - let scriptsig_len = self.ms.max_satisfaction_size()?; - Ok(4 * (varint_len(scriptsig_len) + scriptsig_len)) - } -} - impl ForEachKey for Bare { fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, pred: F) -> bool where @@ -215,6 +225,16 @@ impl Pkh { pub fn into_inner(self) -> Pk { self.pk } + + /// Computes an upper bound on the weight of a satisfying witness to the + /// transaction. + /// + /// Assumes all ec-signatures are 73 bytes, including push opcode and + /// sighash suffix. Includes the weight of the VarInts encoding the + /// scriptSig and witness stack length. + pub fn max_satisfaction_weight(&self) -> usize { + 4 * (1 + 73 + BareCtx::pk_len(&self.pk)) + } } impl Pkh { @@ -240,6 +260,36 @@ impl Pkh { pub fn ecdsa_sighash_script_code(&self) -> Script { self.script_pubkey() } + + /// Returns satisfying non-malleable witness and scriptSig with minimum + /// weight to spend an output controlled by the given descriptor if it is + /// possible to construct one using the `satisfier`. + pub fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, Script), Error> + where + S: Satisfier, + { + if let Some(sig) = satisfier.lookup_ecdsa_sig(&self.pk) { + let sig_vec = sig.to_vec(); + let script_sig = script::Builder::new() + .push_slice(&sig_vec[..]) + .push_key(&self.pk.to_public_key()) + .into_script(); + let witness = vec![]; + Ok((witness, script_sig)) + } else { + Err(Error::MissingSig(self.pk.to_public_key())) + } + } + + /// Returns satisfying, possibly malleable, witness and scriptSig with + /// minimum weight to spend an output controlled by the given descriptor if + /// it is possible to construct one using the `satisfier`. + pub fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, Script), Error> + where + S: Satisfier, + { + self.get_satisfaction(satisfier) + } } impl fmt::Debug for Pkh { @@ -300,38 +350,6 @@ where } } -impl DescriptorTrait for Pkh { - fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, Script), Error> - where - Pk: ToPublicKey, - S: Satisfier, - { - if let Some(sig) = satisfier.lookup_ecdsa_sig(&self.pk) { - let sig_vec = sig.to_vec(); - let script_sig = script::Builder::new() - .push_slice(&sig_vec[..]) - .push_key(&self.pk.to_public_key()) - .into_script(); - let witness = vec![]; - Ok((witness, script_sig)) - } else { - Err(Error::MissingSig(self.pk.to_public_key())) - } - } - - fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, Script), Error> - where - Pk: ToPublicKey, - S: Satisfier, - { - self.get_satisfaction(satisfier) - } - - fn max_satisfaction_weight(&self) -> Result { - Ok(4 * (1 + 73 + BareCtx::pk_len(&self.pk))) - } -} - impl ForEachKey for Pkh { fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool where diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index 647546fb2..13a932bdc 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -69,52 +69,6 @@ pub use self::key::{ /// public key from the descriptor. pub type KeyMap = HashMap; -/// A general trait for Bitcoin descriptor. -/// Offers function for witness cost estimation, script pubkey creation -/// satisfaction using the [Satisfier] trait. -// Unfortunately, the translation function cannot be added to trait -// because of traits cannot know underlying generic of Self. -// Thus, we must implement additional trait for translate function -pub trait DescriptorTrait { - /// Returns satisfying non-malleable witness and scriptSig with minimum weight to spend an - /// output controlled by the given descriptor if it possible to - /// construct one using the satisfier S. - fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, Script), Error> - where - Pk: ToPublicKey, - S: Satisfier; - - /// Returns satisfying, possibly malleable witness and scriptSig to spend an - /// output controlled by the given descriptor if it possible to - /// construct one using the satisfier S. - fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, Script), Error> - where - Pk: ToPublicKey, - S: Satisfier; - - /// Attempts to produce a non-malleable satisfying witness and scriptSig to spend an - /// output controlled by the given descriptor; add the data to a given - /// `TxIn` output. - fn satisfy(&self, txin: &mut TxIn, satisfier: S) -> Result<(), Error> - where - Pk: ToPublicKey, - S: Satisfier, - { - // easy default implementation - let (witness, script_sig) = self.get_satisfaction(satisfier)?; - txin.witness = Witness::from_vec(witness); - txin.script_sig = script_sig; - Ok(()) - } - - /// Computes an upper bound on the weight of a satisfying witness to the - /// transaction. Assumes all ec-signatures are 73 bytes, including push opcode - /// and sighash suffix. Includes the weight of the VarInts encoding the - /// scriptSig and witness stack length. - /// Returns Error when the descriptor is impossible to safisfy (ex: sh(OP_FALSE)) - fn max_satisfaction_weight(&self) -> Result; -} - /// Script descriptor #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Descriptor { @@ -445,45 +399,12 @@ impl Descriptor { Descriptor::Tr(_) => Err(Error::TrNoScriptCode), } } -} -impl TranslatePk for Descriptor

-where - P: MiniscriptKey, - Q: MiniscriptKey, -{ - type Output = Descriptor; - /// Converts a descriptor using abstract keys to one using specific keys. - /// - /// # Panics - /// - /// If `fpk` returns an uncompressed key when converting to a Segwit descriptor. - /// To prevent this panic, ensure `fpk` returns an error in this case instead. - fn translate_pk(&self, mut fpk: Fpk, mut fpkh: Fpkh) -> Result, E> - where - Fpk: FnMut(&P) -> Result, - Fpkh: FnMut(&P::Hash) -> Result, - Q: MiniscriptKey, - { - let desc = match *self { - Descriptor::Bare(ref bare) => Descriptor::Bare(bare.translate_pk(&mut fpk, &mut fpkh)?), - Descriptor::Pkh(ref pk) => Descriptor::Pkh(pk.translate_pk(&mut fpk, &mut fpkh)?), - Descriptor::Wpkh(ref pk) => Descriptor::Wpkh(pk.translate_pk(&mut fpk, &mut fpkh)?), - Descriptor::Sh(ref sh) => Descriptor::Sh(sh.translate_pk(&mut fpk, &mut fpkh)?), - Descriptor::Wsh(ref wsh) => Descriptor::Wsh(wsh.translate_pk(&mut fpk, &mut fpkh)?), - Descriptor::Tr(ref tr) => Descriptor::Tr(tr.translate_pk(&mut fpk, &mut fpkh)?), - }; - Ok(desc) - } -} - -impl DescriptorTrait for Descriptor { /// Returns satisfying non-malleable witness and scriptSig to spend an /// output controlled by the given descriptor if it possible to /// construct one using the satisfier S. - fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, Script), Error> + pub fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, Script), Error> where - Pk: ToPublicKey, S: Satisfier, { match *self { @@ -499,9 +420,8 @@ impl DescriptorTrait for Descriptor { /// Returns a possilbly mallable satisfying non-malleable witness and scriptSig to spend an /// output controlled by the given descriptor if it possible to /// construct one using the satisfier S. - fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, Script), Error> + pub fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, Script), Error> where - Pk: ToPublicKey, S: Satisfier, { match *self { @@ -514,19 +434,68 @@ impl DescriptorTrait for Descriptor { } } + /// Attempts to produce a non-malleable satisfying witness and scriptSig to spend an + /// output controlled by the given descriptor; add the data to a given + /// `TxIn` output. + pub fn satisfy(&self, txin: &mut TxIn, satisfier: S) -> Result<(), Error> + where + S: Satisfier, + { + let (witness, script_sig) = self.get_satisfaction(satisfier)?; + txin.witness = Witness::from_vec(witness); + txin.script_sig = script_sig; + Ok(()) + } + /// Computes an upper bound on the weight of a satisfying witness to the - /// transaction. Assumes all signatures are 73 bytes, including push opcode - /// and sighash suffix. Includes the weight of the VarInts encoding the + /// transaction. + /// + /// Assumes all ec-signatures are 73 bytes, including push opcode and + /// sighash suffix. Includes the weight of the VarInts encoding the /// scriptSig and witness stack length. - fn max_satisfaction_weight(&self) -> Result { - match *self { - Descriptor::Bare(ref bare) => bare.max_satisfaction_weight(), + /// + /// # Errors + /// When the descriptor is impossible to safisfy (ex: sh(OP_FALSE)). + pub fn max_satisfaction_weight(&self) -> Result { + let weight = match *self { + Descriptor::Bare(ref bare) => bare.max_satisfaction_weight()?, Descriptor::Pkh(ref pkh) => pkh.max_satisfaction_weight(), Descriptor::Wpkh(ref wpkh) => wpkh.max_satisfaction_weight(), - Descriptor::Wsh(ref wsh) => wsh.max_satisfaction_weight(), - Descriptor::Sh(ref sh) => sh.max_satisfaction_weight(), - Descriptor::Tr(ref tr) => tr.max_satisfaction_weight(), - } + Descriptor::Wsh(ref wsh) => wsh.max_satisfaction_weight()?, + Descriptor::Sh(ref sh) => sh.max_satisfaction_weight()?, + Descriptor::Tr(ref tr) => tr.max_satisfaction_weight()?, + }; + Ok(weight) + } +} + +impl TranslatePk for Descriptor

+where + P: MiniscriptKey, + Q: MiniscriptKey, +{ + type Output = Descriptor; + /// Converts a descriptor using abstract keys to one using specific keys. + /// + /// # Panics + /// + /// If `fpk` returns an uncompressed key when converting to a Segwit descriptor. + /// To prevent this panic, ensure `fpk` returns an error in this case instead. + fn translate_pk(&self, mut fpk: Fpk, mut fpkh: Fpkh) -> Result, E> + where + Fpk: FnMut(&P) -> Result, + Fpkh: FnMut(&P::Hash) -> Result, + Q: MiniscriptKey, + { + let desc = match *self { + Descriptor::Bare(ref bare) => Descriptor::Bare(bare.translate_pk(&mut fpk, &mut fpkh)?), + Descriptor::Pkh(ref pk) => Descriptor::Pkh(pk.translate_pk(&mut fpk, &mut fpkh)?), + Descriptor::Wpkh(ref pk) => Descriptor::Wpkh(pk.translate_pk(&mut fpk, &mut fpkh)?), + Descriptor::Sh(ref sh) => Descriptor::Sh(sh.translate_pk(&mut fpk, &mut fpkh)?), + Descriptor::Wsh(ref wsh) => Descriptor::Wsh(wsh.translate_pk(&mut fpk, &mut fpkh)?), + Descriptor::Tr(ref tr) => Descriptor::Tr(tr.translate_pk(&mut fpk, &mut fpkh)?), + }; + Ok(desc) } } diff --git a/src/descriptor/segwitv0.rs b/src/descriptor/segwitv0.rs index dc1ee6778..bc452e02c 100644 --- a/src/descriptor/segwitv0.rs +++ b/src/descriptor/segwitv0.rs @@ -22,7 +22,7 @@ use std::str::FromStr; use bitcoin::{self, Address, Network, Script}; use super::checksum::{desc_checksum, verify_checksum}; -use super::{DescriptorTrait, SortedMultiVec}; +use super::SortedMultiVec; use crate::expression::{self, FromTree}; use crate::miniscript::context::{ScriptContext, ScriptContextError}; use crate::policy::{semantic, Liftable}; @@ -83,6 +83,35 @@ impl Wsh { } Ok(()) } + + /// Computes an upper bound on the weight of a satisfying witness to the + /// transaction. + /// + /// Assumes all ec-signatures are 73 bytes, including push opcode and + /// sighash suffix. Includes the weight of the VarInts encoding the + /// scriptSig and witness stack length. + /// + /// # Errors + /// When the descriptor is impossible to safisfy (ex: sh(OP_FALSE)). + pub fn max_satisfaction_weight(&self) -> Result { + 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 + // scriptSig length byte + varint_len(script_size) + + script_size + + varint_len(max_sat_elems) + + max_sat_size) + } } impl Wsh { @@ -111,6 +140,39 @@ impl Wsh { pub fn ecdsa_sighash_script_code(&self) -> Script { self.inner_script() } + + /// Returns satisfying non-malleable witness and scriptSig with minimum + /// weight to spend an output controlled by the given descriptor if it is + /// possible to construct one using the `satisfier`. + pub fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, Script), Error> + where + S: Satisfier, + { + 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 = Script::new(); + Ok((witness, script_sig)) + } + + /// Returns satisfying, possibly malleable, witness and scriptSig with + /// minimum weight to spend an output controlled by the given descriptor if + /// it is possible to construct one using the `satisfier`. + pub fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, Script), Error> + where + S: Satisfier, + { + 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 = Script::new(); + Ok((witness, script_sig)) + } } /// Wsh Inner @@ -193,57 +255,6 @@ where } } -impl DescriptorTrait for Wsh { - fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, Script), Error> - where - Pk: ToPublicKey, - S: Satisfier, - { - 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 = Script::new(); - Ok((witness, script_sig)) - } - - fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, Script), Error> - where - Pk: ToPublicKey, - S: Satisfier, - { - 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 = Script::new(); - Ok((witness, script_sig)) - } - - fn max_satisfaction_weight(&self) -> Result { - 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 + // scriptSig length byte - varint_len(script_size) + - script_size + - varint_len(max_sat_elems) + - max_sat_size) - } -} - impl ForEachKey for Wsh { fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, pred: F) -> bool where @@ -322,6 +333,16 @@ impl Wpkh { Ok(()) } } + + /// Computes an upper bound on the weight of a satisfying witness to the + /// transaction. + /// + /// Assumes all ec-signatures are 73 bytes, including push opcode and + /// sighash suffix. Includes the weight of the VarInts encoding the + /// scriptSig and witness stack length. + pub fn max_satisfaction_weight(&self) -> usize { + 4 + 1 + 73 + Segwitv0::pk_len(&self.pk) + } } impl Wpkh { @@ -352,6 +373,33 @@ impl Wpkh { let addr = Address::p2pkh(&self.pk.to_public_key(), Network::Bitcoin); addr.script_pubkey() } + + /// Returns satisfying non-malleable witness and scriptSig with minimum + /// weight to spend an output controlled by the given descriptor if it is + /// possible to construct one using the `satisfier`. + pub fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, Script), Error> + where + S: Satisfier, + { + if let Some(sig) = satisfier.lookup_ecdsa_sig(&self.pk) { + let sig_vec = sig.to_vec(); + let script_sig = Script::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())) + } + } + + /// Returns satisfying, possibly malleable, witness and scriptSig with + /// minimum weight to spend an output controlled by the given descriptor if + /// it is possible to construct one using the `satisfier`. + pub fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, Script), Error> + where + S: Satisfier, + { + self.get_satisfaction(satisfier) + } } impl fmt::Debug for Wpkh { @@ -412,35 +460,6 @@ where } } -impl DescriptorTrait for Wpkh { - fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, Script), Error> - where - Pk: ToPublicKey, - S: Satisfier, - { - if let Some(sig) = satisfier.lookup_ecdsa_sig(&self.pk) { - let sig_vec = sig.to_vec(); - let script_sig = Script::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())) - } - } - - fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, Script), Error> - where - Pk: ToPublicKey, - S: Satisfier, - { - self.get_satisfaction(satisfier) - } - - fn max_satisfaction_weight(&self) -> Result { - Ok(4 + 1 + 73 + Segwitv0::pk_len(&self.pk)) - } -} - impl ForEachKey for Wpkh { fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool where diff --git a/src/descriptor/sh.rs b/src/descriptor/sh.rs index 4d666a5aa..1c628fde2 100644 --- a/src/descriptor/sh.rs +++ b/src/descriptor/sh.rs @@ -25,7 +25,7 @@ use bitcoin::blockdata::script; use bitcoin::{Address, Network, Script}; use super::checksum::{desc_checksum, verify_checksum}; -use super::{DescriptorTrait, SortedMultiVec, Wpkh, Wsh}; +use super::{SortedMultiVec, Wpkh, Wsh}; use crate::expression::{self, FromTree}; use crate::miniscript::context::ScriptContext; use crate::policy::{semantic, Liftable}; @@ -214,6 +214,36 @@ impl Sh { inner: ShInner::Wpkh(wpkh), } } + + /// Computes an upper bound on the weight of a satisfying witness to the + /// transaction. + /// + /// Assumes all ec-signatures are 73 bytes, including push opcode and + /// sighash suffix. Includes the weight of the VarInts encoding the + /// scriptSig and witness stack length. + /// + /// # Errors + /// When the descriptor is impossible to safisfy (ex: sh(OP_FALSE)). + pub fn max_satisfaction_weight(&self) -> Result { + Ok(match self.inner { + // add weighted script sig, len byte stays the same + 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) + } + // add weighted script sig, len byte stays the same + 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 Sh { @@ -296,12 +326,12 @@ impl Sh { ShInner::SortedMulti(..) | ShInner::Ms(..) => Script::new(), } } -} -impl DescriptorTrait for Sh { - fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, Script), Error> + /// Returns satisfying non-malleable witness and scriptSig with minimum + /// weight to spend an output controlled by the given descriptor if it is + /// possible to construct one using the `satisfier`. + pub fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, Script), Error> where - Pk: ToPublicKey, S: Satisfier, { let script_sig = self.unsigned_script_sig(); @@ -331,9 +361,11 @@ impl DescriptorTrait for Sh { } } - fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, Script), Error> + /// Returns satisfying, possibly malleable, witness and scriptSig with + /// minimum weight to spend an output controlled by the given descriptor if + /// it is possible to construct one using the `satisfier`. + pub fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, Script), Error> where - Pk: ToPublicKey, S: Satisfier, { let script_sig = self.unsigned_script_sig(); @@ -352,27 +384,6 @@ impl DescriptorTrait for Sh { _ => self.get_satisfaction(satisfier), } } - - fn max_satisfaction_weight(&self) -> Result { - Ok(match self.inner { - // add weighted script sig, len byte stays the same - 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) - } - // add weighted script sig, len byte stays the same - 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 ForEachKey for Sh { diff --git a/src/descriptor/tr.rs b/src/descriptor/tr.rs index 7f2c49169..9b063cff1 100644 --- a/src/descriptor/tr.rs +++ b/src/descriptor/tr.rs @@ -19,8 +19,7 @@ use crate::policy::semantic::Policy; use crate::policy::Liftable; use crate::util::{varint_len, witness_size}; use crate::{ - errstr, DescriptorTrait, Error, ForEach, ForEachKey, MiniscriptKey, Satisfier, Tap, - ToPublicKey, TranslatePk, + errstr, Error, ForEach, ForEachKey, MiniscriptKey, Satisfier, Tap, ToPublicKey, TranslatePk, }; /// A Taproot Tree representation. @@ -278,6 +277,39 @@ impl Tr { } Ok(()) } + + /// Computes an upper bound on the weight of a satisfying witness to the + /// transaction. + /// + /// Assumes all ec-signatures are 73 bytes, including push opcode and + /// sighash suffix. Includes the weight of the VarInts encoding the + /// scriptSig and witness stack length. + /// + /// # Errors + /// When the descriptor is impossible to safisfy (ex: sh(OP_FALSE)). + pub fn max_satisfaction_weight(&self) -> Result { + let mut max_wieght = Some(65); + for (depth, ms) in self.iter_scripts() { + let script_size = ms.script_size(); + let max_sat_elems = match ms.max_satisfaction_witness_elements() { + Ok(elem) => elem, + Err(..) => continue, + }; + let max_sat_size = match ms.max_satisfaction_size() { + Ok(sz) => sz, + Err(..) => continue, + }; + let control_block_sz = control_block_len(depth); + let wit_size = 4 + // scriptSig len byte + control_block_sz + // first element control block + varint_len(script_size) + + script_size + // second element script len with prefix + varint_len(max_sat_elems) + + max_sat_size; // witness + max_wieght = cmp::max(max_wieght, Some(wit_size)); + } + max_wieght.ok_or(Error::ImpossibleSatisfaction) + } } impl Tr { @@ -296,6 +328,26 @@ impl Tr { let spend_info = self.spend_info(); Address::p2tr_tweaked(spend_info.output_key(), network) } + + /// Returns satisfying non-malleable witness and scriptSig with minimum + /// weight to spend an output controlled by the given descriptor if it is + /// possible to construct one using the `satisfier`. + pub fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, Script), Error> + where + S: Satisfier, + { + best_tap_spend(self, satisfier, false /* allow_mall */) + } + + /// Returns satisfying, possibly malleable, witness and scriptSig with + /// minimum weight to spend an output controlled by the given descriptor if + /// it is possible to construct one using the `satisfier`. + pub fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, Script), Error> + where + S: Satisfier, + { + best_tap_spend(self, satisfier, true /* allow_mall */) + } } /// Iterator for Taproot structures @@ -553,48 +605,6 @@ impl Liftable for Tr { } } -impl DescriptorTrait for Tr { - fn get_satisfaction(&self, satisfier: S) -> Result<(Vec>, Script), Error> - where - Pk: ToPublicKey, - S: Satisfier, - { - best_tap_spend(self, satisfier, false /* allow_mall */) - } - - fn get_satisfaction_mall(&self, satisfier: S) -> Result<(Vec>, Script), Error> - where - Pk: ToPublicKey, - S: Satisfier, - { - best_tap_spend(self, satisfier, true /* allow_mall */) - } - - fn max_satisfaction_weight(&self) -> Result { - let mut max_wieght = Some(65); - for (depth, ms) in self.iter_scripts() { - let script_size = ms.script_size(); - let max_sat_elems = match ms.max_satisfaction_witness_elements() { - Ok(elem) => elem, - Err(..) => continue, - }; - let max_sat_size = match ms.max_satisfaction_size() { - Ok(sz) => sz, - Err(..) => continue, - }; - let control_block_sz = control_block_len(depth); - let wit_size = 4 + // scriptSig len byte - control_block_sz + // first element control block - varint_len(script_size) + - script_size + // second element script len with prefix - varint_len(max_sat_elems) + - max_sat_size; // witness - max_wieght = cmp::max(max_wieght, Some(wit_size)); - } - max_wieght.ok_or(Error::ImpossibleSatisfaction) - } -} - impl ForEachKey for Tr { fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool where diff --git a/src/lib.rs b/src/lib.rs index d46450b5a..5c061a07a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,7 +54,6 @@ //! //! ```rust //! use std::str::FromStr; -//! use miniscript::DescriptorTrait; //! //! let desc = miniscript::Descriptor::::from_str("\ //! sh(wsh(or_d(\ @@ -114,7 +113,7 @@ use std::{error, fmt, hash, str}; use bitcoin::blockdata::{opcodes, script}; use bitcoin::hashes::{hash160, sha256, Hash}; -pub use crate::descriptor::{Descriptor, DescriptorPublicKey, DescriptorTrait}; +pub use crate::descriptor::{Descriptor, DescriptorPublicKey}; pub use crate::interpreter::Interpreter; pub use crate::miniscript::context::{BareCtx, Legacy, ScriptContext, Segwitv0, Tap}; pub use crate::miniscript::decode::Terminal; @@ -706,7 +705,7 @@ impl fmt::Display for Error { write!(f, "MultiA too many keys {}", k) } Error::TaprootSpendInfoUnavialable => { - write!(f, "Taproot Spend Info not computed. Hint: Did you call `compute_spend_info` before calling methods from DescriptorTrait") + write!(f, "Taproot Spend Info not computed.") } Error::TrNoScriptCode => { write!(f, "No script code for Tr descriptors") diff --git a/src/psbt/finalizer.rs b/src/psbt/finalizer.rs index bc95bf3be..bb5de4455 100644 --- a/src/psbt/finalizer.rs +++ b/src/psbt/finalizer.rs @@ -29,7 +29,6 @@ use bitcoin::util::taproot::LeafVersion; use bitcoin::{self, PublicKey, Script, TxOut}; use super::{sanity_check, Error, InputError, Psbt, PsbtInputSatisfier}; -use crate::descriptor::DescriptorTrait; use crate::util::witness_size; use crate::{interpreter, BareCtx, Descriptor, Legacy, Miniscript, Satisfier, Segwitv0, Tap};