Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tr descriptor #278

Merged
merged 12 commits into from
Feb 9, 2022
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