Skip to content

Commit 74460e7

Browse files
committed
Update descriptor trait
1 parent a0ef37f commit 74460e7

File tree

7 files changed

+263
-90
lines changed

7 files changed

+263
-90
lines changed

examples/htlc.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ extern crate bitcoin;
1818
extern crate miniscript;
1919

2020
use bitcoin::Network;
21+
use miniscript::descriptor::Wsh;
2122
use miniscript::policy::{Concrete, Liftable};
22-
use miniscript::{Descriptor, DescriptorTrait};
23+
use miniscript::DescriptorTrait;
2324
use std::str::FromStr;
2425

2526
fn main() {
@@ -31,7 +32,7 @@ fn main() {
3132
expiry = "4444"
3233
)).unwrap();
3334

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

5657
assert_eq!(
57-
format!("{:x}", htlc_descriptor.script_pubkey()),
58+
format!("{:x}", htlc_descriptor.spk()),
5859
"0020d853877af928a8d2a569c9c0ed14bd16f6a80ce9cccaf8a6150fd8f7f8867ae2"
5960
);
6061

6162
assert_eq!(
62-
format!("{:x}", htlc_descriptor.explicit_script()),
63+
format!("{:x}", htlc_descriptor.inner_script()),
6364
"21022222222222222222222222222222222222222222222222222222222222222222ac6476a91451814f108670aced2d77c1805ddd6634bc9d473188ad025c11b26782012088a82011111111111111111111111111111111111111111111111111111111111111118768"
6465
);
6566

examples/parse.rs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
extern crate bitcoin;
1818
extern crate miniscript;
1919

20-
use miniscript::{descriptor::DescriptorType, DescriptorTrait};
20+
use miniscript::{descriptor::DescriptorType, Descriptor, DescriptorTrait};
2121
use std::str::FromStr;
2222

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

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

42+
// Another way to compute script pubkey
43+
// We can also compute the type of descriptor
44+
let desc_type = my_descriptor.desc_type();
45+
assert_eq!(desc_type, DescriptorType::Wsh);
46+
// Since we know the type of descriptor, we can get the Wsh struct from Descriptor
47+
// This allows us to call infallible methods for getting script pubkey
48+
if let Descriptor::Wsh(wsh) = &my_descriptor {
49+
assert_eq!(
50+
format!("{:x}", wsh.spk()),
51+
"0020daef16dd7c946a3e735a6e43310cb2ce33dfd14a04f76bf8241a16654cb2f0f9"
52+
);
53+
} else {
54+
// We checked for the descriptor type earlier
55+
}
56+
57+
// Get the inner script inside the descriptor
4458
assert_eq!(
45-
format!("{:x}", my_descriptor.explicit_script()),
59+
format!(
60+
"{:x}",
61+
my_descriptor
62+
.explicit_script()
63+
.expect("Wsh descriptors have inner scripts")
64+
),
4665
"21020202020202020202020202020202020202020202020202020202020202020202ac"
4766
);
4867

examples/sign_multisig.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,12 @@ fn main() {
101101
);
102102

103103
assert_eq!(
104-
format!("{:x}", my_descriptor.explicit_script()),
104+
format!(
105+
"{:x}",
106+
my_descriptor
107+
.explicit_script()
108+
.expect("wsh descriptors have unique inner script")
109+
),
105110
"52\
106111
21020202020202020202020202020202020202020202020202020202020202020202\
107112
21020102030405060708010203040506070801020304050607080000000000000000\

src/descriptor/bare.rs

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,26 @@ impl<Pk: MiniscriptKey> Bare<Pk> {
6363
}
6464
}
6565

66+
impl<Pk: MiniscriptKey + ToPublicKey> Bare<Pk> {
67+
/// Obtain the corresponding script pubkey for this descriptor
68+
/// Non failing verion of [`DescriptorTrait::script_pubkey`] for this descriptor
69+
pub fn spk(&self) -> Script {
70+
self.ms.encode()
71+
}
72+
73+
/// Obtain the underlying miniscript for this descriptor
74+
/// Non failing verion of [`DescriptorTrait::explicit_script`] for this descriptor
75+
pub fn inner_script(&self) -> Script {
76+
self.spk()
77+
}
78+
79+
/// Obtain the pre bip-340 signature script code for this descriptor
80+
/// Non failing verion of [`DescriptorTrait::script_code`] for this descriptor
81+
pub fn ecdsa_sighash_script_code(&self) -> Script {
82+
self.spk()
83+
}
84+
}
85+
6686
impl<Pk: MiniscriptKey> fmt::Debug for Bare<Pk> {
6787
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6888
write!(f, "{:?}", self.ms)
@@ -130,7 +150,7 @@ impl<Pk: MiniscriptKey> DescriptorTrait<Pk> for Bare<Pk> {
130150
where
131151
Pk: ToPublicKey,
132152
{
133-
self.ms.encode()
153+
self.spk()
134154
}
135155

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

143-
fn explicit_script(&self) -> Script
163+
fn explicit_script(&self) -> Result<Script, Error>
144164
where
145165
Pk: ToPublicKey,
146166
{
147-
self.ms.encode()
167+
Ok(self.inner_script())
148168
}
149169

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

177-
fn script_code(&self) -> Script
197+
fn script_code(&self) -> Result<Script, Error>
178198
where
179199
Pk: ToPublicKey,
180200
{
181-
self.script_pubkey()
201+
Ok(self.ecdsa_sighash_script_code())
182202
}
183203
}
184204

@@ -238,6 +258,33 @@ impl<Pk: MiniscriptKey> Pkh<Pk> {
238258
}
239259
}
240260

261+
impl<Pk: MiniscriptKey + ToPublicKey> Pkh<Pk> {
262+
/// Obtain the corresponding script pubkey for this descriptor
263+
/// Non failing verion of [`DescriptorTrait::script_pubkey`] for this descriptor
264+
pub fn spk(&self) -> Script {
265+
let addr = bitcoin::Address::p2pkh(&self.pk.to_public_key(), bitcoin::Network::Bitcoin);
266+
addr.script_pubkey()
267+
}
268+
269+
/// Obtain the corresponding script pubkey for this descriptor
270+
/// Non failing verion of [`DescriptorTrait::address`] for this descriptor
271+
pub fn addr(&self, network: bitcoin::Network) -> bitcoin::Address {
272+
bitcoin::Address::p2pkh(&self.pk.to_public_key(), network)
273+
}
274+
275+
/// Obtain the underlying miniscript for this descriptor
276+
/// Non failing verion of [`DescriptorTrait::explicit_script`] for this descriptor
277+
pub fn inner_script(&self) -> Script {
278+
self.spk()
279+
}
280+
281+
/// Obtain the pre bip-340 signature script code for this descriptor
282+
/// Non failing verion of [`DescriptorTrait::script_code`] for this descriptor
283+
pub fn ecdsa_sighash_script_code(&self) -> Script {
284+
self.spk()
285+
}
286+
}
287+
241288
impl<Pk: MiniscriptKey> fmt::Debug for Pkh<Pk> {
242289
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
243290
write!(f, "pkh({:?})", self.pk)
@@ -305,15 +352,14 @@ impl<Pk: MiniscriptKey> DescriptorTrait<Pk> for Pkh<Pk> {
305352
where
306353
Pk: ToPublicKey,
307354
{
308-
Ok(bitcoin::Address::p2pkh(&self.pk.to_public_key(), network))
355+
Ok(self.addr(network))
309356
}
310357

311358
fn script_pubkey(&self) -> Script
312359
where
313360
Pk: ToPublicKey,
314361
{
315-
let addr = bitcoin::Address::p2pkh(&self.pk.to_public_key(), bitcoin::Network::Bitcoin);
316-
addr.script_pubkey()
362+
self.spk()
317363
}
318364

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

326-
fn explicit_script(&self) -> Script
372+
fn explicit_script(&self) -> Result<Script, Error>
327373
where
328374
Pk: ToPublicKey,
329375
{
330-
self.script_pubkey()
376+
Ok(self.inner_script())
331377
}
332378

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

363-
fn script_code(&self) -> Script
409+
fn script_code(&self) -> Result<Script, Error>
364410
where
365411
Pk: ToPublicKey,
366412
{
367-
self.script_pubkey()
413+
Ok(self.ecdsa_sighash_script_code())
368414
}
369415
}
370416

src/descriptor/mod.rs

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ pub trait DescriptorTrait<Pk: MiniscriptKey> {
8989

9090
/// Computes the Bitcoin address of the descriptor, if one exists
9191
/// Some descriptors like pk() don't have any address.
92+
/// Errors:
93+
/// - On raw/bare descriptors that don't have any address
94+
/// - In Tr descriptors where the precomputed spend data is not available
9295
fn address(&self, network: bitcoin::Network) -> Result<bitcoin::Address, Error>
9396
where
9497
Pk: ToPublicKey;
@@ -114,11 +117,12 @@ pub trait DescriptorTrait<Pk: MiniscriptKey> {
114117
/// script before any hashing is done. For `Bare`, `Pkh` and `Wpkh` this
115118
/// is the scriptPubkey; for `ShWpkh` and `Sh` this is the redeemScript;
116119
/// for the others it is the witness script.
117-
fn explicit_script(&self) -> Script
120+
/// For `Tr` descriptors, this will error as there is no underlying script
121+
fn explicit_script(&self) -> Result<Script, Error>
118122
where
119123
Pk: ToPublicKey;
120124

121-
/// Returns satisfying non-malleable witness and scriptSig to spend an
125+
/// Returns satisfying non-malleable witness and scriptSig with minimum weight to spend an
122126
/// output controlled by the given descriptor if it possible to
123127
/// construct one using the satisfier S.
124128
fn get_satisfaction<S>(&self, satisfier: S) -> Result<(Vec<Vec<u8>>, Script), Error>
@@ -150,7 +154,7 @@ pub trait DescriptorTrait<Pk: MiniscriptKey> {
150154
}
151155

152156
/// Computes an upper bound on the weight of a satisfying witness to the
153-
/// transaction. Assumes all signatures are 73 bytes, including push opcode
157+
/// transaction. Assumes all ec-signatures are 73 bytes, including push opcode
154158
/// and sighash suffix. Includes the weight of the VarInts encoding the
155159
/// scriptSig and witness stack length.
156160
/// Returns Error when the descriptor is impossible to safisfy (ex: sh(OP_FALSE))
@@ -160,7 +164,9 @@ pub trait DescriptorTrait<Pk: MiniscriptKey> {
160164
///
161165
/// The `scriptCode` is the Script of the previous transaction output being serialized in the
162166
/// sighash when evaluating a `CHECKSIG` & co. OP code.
163-
fn script_code(&self) -> Script
167+
/// Errors:
168+
/// - When the descriptor is Tr
169+
fn script_code(&self) -> Result<Script, Error>
164170
where
165171
Pk: ToPublicKey;
166172
}
@@ -420,7 +426,9 @@ impl<Pk: MiniscriptKey> DescriptorTrait<Pk> for Descriptor<Pk> {
420426
/// script before any hashing is done. For `Bare`, `Pkh` and `Wpkh` this
421427
/// is the scriptPubkey; for `ShWpkh` and `Sh` this is the redeemScript;
422428
/// for the others it is the witness script.
423-
fn explicit_script(&self) -> Script
429+
/// Errors:
430+
/// - When the descriptor is Tr
431+
fn explicit_script(&self) -> Result<Script, Error>
424432
where
425433
Pk: ToPublicKey,
426434
{
@@ -485,7 +493,8 @@ impl<Pk: MiniscriptKey> DescriptorTrait<Pk> for Descriptor<Pk> {
485493
///
486494
/// The `scriptCode` is the Script of the previous transaction output being serialized in the
487495
/// sighash when evaluating a `CHECKSIG` & co. OP code.
488-
fn script_code(&self) -> Script
496+
/// Returns Error for Tr descriptors
497+
fn script_code(&self) -> Result<Script, Error>
489498
where
490499
Pk: ToPublicKey,
491500
{
@@ -1099,7 +1108,7 @@ mod tests {
10991108
#[test]
11001109
fn after_is_cltv() {
11011110
let descriptor = Descriptor::<bitcoin::PublicKey>::from_str("wsh(after(1000))").unwrap();
1102-
let script = descriptor.explicit_script();
1111+
let script = descriptor.explicit_script().unwrap();
11031112

11041113
let actual_instructions: Vec<_> = script.instructions().collect();
11051114
let check = actual_instructions.last().unwrap();
@@ -1110,7 +1119,7 @@ mod tests {
11101119
#[test]
11111120
fn older_is_csv() {
11121121
let descriptor = Descriptor::<bitcoin::PublicKey>::from_str("wsh(older(1000))").unwrap();
1113-
let script = descriptor.explicit_script();
1122+
let script = descriptor.explicit_script().unwrap();
11141123

11151124
let actual_instructions: Vec<_> = script.instructions().collect();
11161125
let check = actual_instructions.last().unwrap();
@@ -1250,7 +1259,7 @@ mod tests {
12501259
)
12511260
.unwrap();
12521261
assert_eq!(
1253-
*descriptor.script_code().as_bytes(),
1262+
*descriptor.script_code().unwrap().as_bytes(),
12541263
Vec::<u8>::from_hex("76a9141d0f172a0ecb48aee1be1f2687d2963ae33f71a188ac").unwrap()[..]
12551264
);
12561265

@@ -1260,7 +1269,7 @@ mod tests {
12601269
)
12611270
.unwrap();
12621271
assert_eq!(
1263-
*descriptor.script_code().as_bytes(),
1272+
*descriptor.script_code().unwrap().as_bytes(),
12641273
Vec::<u8>::from_hex("76a91479091972186c449eb1ded22b78e40d009bdf008988ac").unwrap()[..]
12651274
);
12661275

@@ -1271,7 +1280,7 @@ mod tests {
12711280
.unwrap();
12721281
assert_eq!(
12731282
*descriptor
1274-
.script_code()
1283+
.script_code().unwrap()
12751284
.as_bytes(),
12761285
Vec::<u8>::from_hex("522103789ed0bb717d88f7d321a368d905e7430207ebbd82bd342cf11ae157a7ace5fd2103dbc6764b8884a92e871274b87583e6d5c2a58819473e17e107ef3f6aa5a6162652ae").unwrap()[..]
12771286
);
@@ -1280,7 +1289,7 @@ mod tests {
12801289
let descriptor = Descriptor::<PublicKey>::from_str("sh(wsh(multi(2,03789ed0bb717d88f7d321a368d905e7430207ebbd82bd342cf11ae157a7ace5fd,03dbc6764b8884a92e871274b87583e6d5c2a58819473e17e107ef3f6aa5a61626)))").unwrap();
12811290
assert_eq!(
12821291
*descriptor
1283-
.script_code()
1292+
.script_code().unwrap()
12841293
.as_bytes(),
12851294
Vec::<u8>::from_hex("522103789ed0bb717d88f7d321a368d905e7430207ebbd82bd342cf11ae157a7ace5fd2103dbc6764b8884a92e871274b87583e6d5c2a58819473e17e107ef3f6aa5a6162652ae")
12861295
.unwrap()[..]

0 commit comments

Comments
 (0)