Skip to content
9 changes: 5 additions & 4 deletions examples/htlc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ extern crate bitcoin;
extern crate miniscript;

use bitcoin::Network;
use miniscript::descriptor::Wsh;
use miniscript::policy::{Concrete, Liftable};
use miniscript::{Descriptor, DescriptorTrait};
use miniscript::DescriptorTrait;
use std::str::FromStr;

fn main() {
Expand All @@ -31,7 +32,7 @@ fn main() {
expiry = "4444"
)).unwrap();

let htlc_descriptor = Descriptor::new_wsh(
let htlc_descriptor = Wsh::new(
htlc_policy
.compile()
.expect("Policy compilation only fails on resource limits or mixed timelocks"),
Expand All @@ -54,12 +55,12 @@ fn main() {
);

assert_eq!(
format!("{:x}", htlc_descriptor.script_pubkey()),
format!("{:x}", htlc_descriptor.spk()),
"0020d853877af928a8d2a569c9c0ed14bd16f6a80ce9cccaf8a6150fd8f7f8867ae2"
);

assert_eq!(
format!("{:x}", htlc_descriptor.explicit_script()),
format!("{:x}", htlc_descriptor.inner_script()),
"21022222222222222222222222222222222222222222222222222222222222222222ac6476a91451814f108670aced2d77c1805ddd6634bc9d473188ad025c11b26782012088a82011111111111111111111111111111111111111111111111111111111111111118768"
);

Expand Down
31 changes: 25 additions & 6 deletions examples/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
extern crate bitcoin;
extern crate miniscript;

use miniscript::{descriptor::DescriptorType, DescriptorTrait};
use miniscript::{descriptor::DescriptorType, Descriptor, DescriptorTrait};
use std::str::FromStr;

fn main() {
Expand All @@ -32,17 +32,36 @@ fn main() {
// Or they contain a combination of timelock and heightlock.
assert!(my_descriptor.sanity_check().is_ok());

// Sometimes it is necesarry to have additional information to get the bitcoin::PublicKey
// from the MiniscriptKey which can supplied by `to_pk_ctx` parameter. For example,
// when calculating the script pubkey of a descriptor with xpubs, the secp context and
// child information maybe required.
// Compute the script pubkey. As mentioned in the documentation, script_pubkey only fails
// for Tr descriptors that don't have some pre-computed data
assert_eq!(
format!("{:x}", my_descriptor.script_pubkey()),
"0020daef16dd7c946a3e735a6e43310cb2ce33dfd14a04f76bf8241a16654cb2f0f9"
);

// Another way to compute script pubkey
// We can also compute the type of descriptor
let desc_type = my_descriptor.desc_type();
assert_eq!(desc_type, DescriptorType::Wsh);
// Since we know the type of descriptor, we can get the Wsh struct from Descriptor
// This allows us to call infallible methods for getting script pubkey
if let Descriptor::Wsh(wsh) = &my_descriptor {
assert_eq!(
format!("{:x}", wsh.spk()),
"0020daef16dd7c946a3e735a6e43310cb2ce33dfd14a04f76bf8241a16654cb2f0f9"
);
} else {
// We checked for the descriptor type earlier
}

// Get the inner script inside the descriptor
assert_eq!(
format!("{:x}", my_descriptor.explicit_script()),
format!(
"{:x}",
my_descriptor
.explicit_script()
.expect("Wsh descriptors have inner scripts")
),
"21020202020202020202020202020202020202020202020202020202020202020202ac"
);

Expand Down
7 changes: 6 additions & 1 deletion examples/sign_multisig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,12 @@ fn main() {
);

assert_eq!(
format!("{:x}", my_descriptor.explicit_script()),
format!(
"{:x}",
my_descriptor
.explicit_script()
.expect("wsh descriptors have unique inner script")
),
"52\
21020202020202020202020202020202020202020202020202020202020202020202\
21020102030405060708010203040506070801020304050607080000000000000000\
Expand Down
70 changes: 58 additions & 12 deletions src/descriptor/bare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,26 @@ impl<Pk: MiniscriptKey> Bare<Pk> {
}
}

impl<Pk: MiniscriptKey + ToPublicKey> Bare<Pk> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think all this non-failing methods can be re-organized into an additional trait, let's say PreTaprootDescriptor: Descriptor, such that all pre-taproot descriptor types may be used as a generalized function arguments

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could do for the release. But I think that the effort is not worth it considering everything will go back to non-fallible once we have a new major breaking release of rust-secp that has static contexts

/// Obtain the corresponding script pubkey for this descriptor
/// Non failing verion of [`DescriptorTrait::script_pubkey`] for this descriptor
pub fn spk(&self) -> Script {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commit also adds inner non-failable versions. I am using different names spk instead of script_pubkey and inner_script in place of explicit_script and ecdsa_sighash_script_code instead of scrpit_code . I am still debating whether I should rename those or have the same function name.

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()
}

/// 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()
}
}

impl<Pk: MiniscriptKey> fmt::Debug for Bare<Pk> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self.ms)
Expand Down Expand Up @@ -130,7 +150,7 @@ impl<Pk: MiniscriptKey> DescriptorTrait<Pk> for Bare<Pk> {
where
Pk: ToPublicKey,
{
self.ms.encode()
self.spk()
}

fn unsigned_script_sig(&self) -> Script
Expand All @@ -140,11 +160,11 @@ impl<Pk: MiniscriptKey> DescriptorTrait<Pk> for Bare<Pk> {
Script::new()
}

fn explicit_script(&self) -> Script
fn explicit_script(&self) -> Result<Script, Error>
where
Pk: ToPublicKey,
{
self.ms.encode()
Ok(self.inner_script())
}

fn get_satisfaction<S>(&self, satisfier: S) -> Result<(Vec<Vec<u8>>, Script), Error>
Expand Down Expand Up @@ -174,11 +194,11 @@ impl<Pk: MiniscriptKey> DescriptorTrait<Pk> for Bare<Pk> {
Ok(4 * (varint_len(scriptsig_len) + scriptsig_len))
}

fn script_code(&self) -> Script
fn script_code(&self) -> Result<Script, Error>
where
Pk: ToPublicKey,
{
self.script_pubkey()
Ok(self.ecdsa_sighash_script_code())
}
}

Expand Down Expand Up @@ -238,6 +258,33 @@ impl<Pk: MiniscriptKey> Pkh<Pk> {
}
}

impl<Pk: MiniscriptKey + ToPublicKey> Pkh<Pk> {
/// 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);
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)
}

/// 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()
}

/// 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()
}
}

impl<Pk: MiniscriptKey> fmt::Debug for Pkh<Pk> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "pkh({:?})", self.pk)
Expand Down Expand Up @@ -305,15 +352,14 @@ impl<Pk: MiniscriptKey> DescriptorTrait<Pk> for Pkh<Pk> {
where
Pk: ToPublicKey,
{
Ok(bitcoin::Address::p2pkh(&self.pk.to_public_key(), network))
Ok(self.addr(network))
}

fn script_pubkey(&self) -> Script
where
Pk: ToPublicKey,
{
let addr = bitcoin::Address::p2pkh(&self.pk.to_public_key(), bitcoin::Network::Bitcoin);
addr.script_pubkey()
self.spk()
}

fn unsigned_script_sig(&self) -> Script
Expand All @@ -323,11 +369,11 @@ impl<Pk: MiniscriptKey> DescriptorTrait<Pk> for Pkh<Pk> {
Script::new()
}

fn explicit_script(&self) -> Script
fn explicit_script(&self) -> Result<Script, Error>
where
Pk: ToPublicKey,
{
self.script_pubkey()
Ok(self.inner_script())
}

fn get_satisfaction<S>(&self, satisfier: S) -> Result<(Vec<Vec<u8>>, Script), Error>
Expand Down Expand Up @@ -360,11 +406,11 @@ impl<Pk: MiniscriptKey> DescriptorTrait<Pk> for Pkh<Pk> {
Ok(4 * (1 + 73 + BareCtx::pk_len(&self.pk)))
}

fn script_code(&self) -> Script
fn script_code(&self) -> Result<Script, Error>
where
Pk: ToPublicKey,
{
self.script_pubkey()
Ok(self.ecdsa_sighash_script_code())
}
}

Expand Down
Loading