Skip to content

Commit fe66a21

Browse files
committed
Extract the script_code method out of DescriptorTrait
The code around the `script_code` method is a little convoluted because a taproot descriptor does not support it. Extract the `script_code` method out of the `DescriptorTrait` as a new `ScriptCode` trait that is infallible. Implement it for all the descriptor types except taproot.
1 parent ebbb170 commit fe66a21

File tree

7 files changed

+76
-169
lines changed

7 files changed

+76
-169
lines changed

src/descriptor/bare.rs

Lines changed: 13 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use crate::{
3333

3434
use super::{
3535
checksum::{desc_checksum, verify_checksum},
36-
DescriptorTrait, ExplicitScript, ToAddress,
36+
DescriptorTrait, ExplicitScript, ScriptCode, ToAddress,
3737
};
3838

3939
/// Create a Bare Descriptor. That is descriptor that is
@@ -63,15 +63,6 @@ impl<Pk: MiniscriptKey> Bare<Pk> {
6363
}
6464
}
6565

66-
impl<Pk: MiniscriptKey + ToPublicKey> Bare<Pk> {
67-
/// Obtains the pre bip-340 signature script code for this descriptor.
68-
/// Called by [`DescriptorTrait::script_code`] for this descriptor.
69-
/// Equivalent to [`DescriptorTrait::script_pubkey`] for this descriptor.
70-
pub fn ecdsa_sighash_script_code(&self) -> Script {
71-
self.script_pubkey()
72-
}
73-
}
74-
7566
impl<Pk: MiniscriptKey> fmt::Debug for Bare<Pk> {
7667
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
7768
write!(f, "{:?}", self.ms)
@@ -168,13 +159,6 @@ impl<Pk: MiniscriptKey> DescriptorTrait<Pk> for Bare<Pk> {
168159
let scriptsig_len = self.ms.max_satisfaction_size()?;
169160
Ok(4 * (varint_len(scriptsig_len) + scriptsig_len))
170161
}
171-
172-
fn script_code(&self) -> Result<Script, Error>
173-
where
174-
Pk: ToPublicKey,
175-
{
176-
Ok(self.ecdsa_sighash_script_code())
177-
}
178162
}
179163

180164
impl<Pk: MiniscriptKey + ToPublicKey> ExplicitScript<Pk> for Bare<Pk> {
@@ -183,6 +167,12 @@ impl<Pk: MiniscriptKey + ToPublicKey> ExplicitScript<Pk> for Bare<Pk> {
183167
}
184168
}
185169

170+
impl<Pk: MiniscriptKey + ToPublicKey> ScriptCode<Pk> for Bare<Pk> {
171+
fn script_code(&self) -> Script {
172+
self.script_pubkey()
173+
}
174+
}
175+
186176
impl<Pk: MiniscriptKey> ForEachKey<Pk> for Bare<Pk> {
187177
fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, pred: F) -> bool
188178
where
@@ -239,15 +229,6 @@ impl<Pk: MiniscriptKey> Pkh<Pk> {
239229
}
240230
}
241231

242-
impl<Pk: MiniscriptKey + ToPublicKey> Pkh<Pk> {
243-
/// Obtain the pre bip-340 signature script code for this descriptor.
244-
/// Called by [`DescriptorTrait::script_code`] for this descriptor.
245-
/// Equivalent to [`DescriptorTrait::script_pubkey`] for this descriptor.
246-
pub fn ecdsa_sighash_script_code(&self) -> Script {
247-
self.script_pubkey()
248-
}
249-
}
250-
251232
impl<Pk: MiniscriptKey> fmt::Debug for Pkh<Pk> {
252233
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
253234
write!(f, "pkh({:?})", self.pk)
@@ -356,13 +337,6 @@ impl<Pk: MiniscriptKey> DescriptorTrait<Pk> for Pkh<Pk> {
356337
fn max_satisfaction_weight(&self) -> Result<usize, Error> {
357338
Ok(4 * (1 + 73 + BareCtx::pk_len(&self.pk)))
358339
}
359-
360-
fn script_code(&self) -> Result<Script, Error>
361-
where
362-
Pk: ToPublicKey,
363-
{
364-
Ok(self.ecdsa_sighash_script_code())
365-
}
366340
}
367341

368342
impl<Pk: MiniscriptKey + ToPublicKey> ToAddress<Pk> for Pkh<Pk> {
@@ -377,6 +351,12 @@ impl<Pk: MiniscriptKey + ToPublicKey> ExplicitScript<Pk> for Pkh<Pk> {
377351
}
378352
}
379353

354+
impl<Pk: MiniscriptKey + ToPublicKey> ScriptCode<Pk> for Pkh<Pk> {
355+
fn script_code(&self) -> Script {
356+
self.script_pubkey()
357+
}
358+
}
359+
380360
impl<Pk: MiniscriptKey> ForEachKey<Pk> for Pkh<Pk> {
381361
fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool
382362
where

src/descriptor/mod.rs

Lines changed: 27 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -146,16 +146,6 @@ pub trait DescriptorTrait<Pk: MiniscriptKey> {
146146
/// scriptSig and witness stack length.
147147
/// Returns Error when the descriptor is impossible to safisfy (ex: sh(OP_FALSE))
148148
fn max_satisfaction_weight(&self) -> Result<usize, Error>;
149-
150-
/// Get the `scriptCode` of a transaction output.
151-
///
152-
/// The `scriptCode` is the Script of the previous transaction output being serialized in the
153-
/// sighash when evaluating a `CHECKSIG` & co. OP code.
154-
/// Errors:
155-
/// - When the descriptor is Tr
156-
fn script_code(&self) -> Result<Script, Error>
157-
where
158-
Pk: ToPublicKey;
159149
}
160150

161151
/// A trait for getting the address for a descriptor.
@@ -173,6 +163,13 @@ pub trait ExplicitScript<Pk: MiniscriptKey + ToPublicKey> {
173163
fn explicit_script(&self) -> Script;
174164
}
175165

166+
/// A trait for getting the `scriptCode` of a transaction output.
167+
pub trait ScriptCode<Pk: MiniscriptKey + ToPublicKey> {
168+
/// The `scriptCode` is the Script of the previous transaction output being
169+
/// serialized in the sighash when evaluating a `CHECKSIG` & co. OP code.
170+
fn script_code(&self) -> Script;
171+
}
172+
176173
/// Script descriptor
177174
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
178175
pub enum Descriptor<Pk: MiniscriptKey> {
@@ -221,6 +218,25 @@ impl<Pk: MiniscriptKey + ToPublicKey> Descriptor<Pk> {
221218
Descriptor::Tr(_) => Err(Error::TrNoScriptCode),
222219
}
223220
}
221+
222+
/// Get the `scriptCode` of a transaction output.
223+
///
224+
/// The `scriptCode` is the Script of the previous transaction output being
225+
/// serialized in the sighash when evaluating a `CHECKSIG` & co. OP code.
226+
///
227+
/// # Errors
228+
///
229+
/// If the descriptor is a taproot descriptor (`Tr`).
230+
pub fn script_code(&self) -> Result<Script, Error> {
231+
match self {
232+
Descriptor::Bare(ref bare) => Ok(bare.script_code()),
233+
Descriptor::Pkh(ref pkh) => Ok(pkh.script_code()),
234+
Descriptor::Wpkh(ref wpkh) => Ok(wpkh.script_code()),
235+
Descriptor::Wsh(ref wsh) => Ok(wsh.script_code()),
236+
Descriptor::Sh(ref sh) => Ok(sh.script_code()),
237+
Descriptor::Tr(_r) => Err(Error::TrNoScriptCode),
238+
}
239+
}
224240
}
225241

226242
impl<Pk: MiniscriptKey> From<Bare<Pk>> for Descriptor<Pk> {
@@ -440,20 +456,13 @@ impl<Pk: MiniscriptKey> Descriptor<Pk> {
440456
/// ```
441457
/// use std::str::FromStr;
442458
/// use miniscript::descriptor::Descriptor;
443-
/// use miniscript::{PreTaprootDescriptor, PreTaprootDescriptorTrait};
459+
/// use miniscript::{PreTaprootDescriptor, PreTaprootDescriptorTrait, ScriptCode};
444460
/// use miniscript::bitcoin;
445461
///
446462
/// // A descriptor with a string generic
447463
/// let desc = Descriptor::<bitcoin::PublicKey>::from_str("wpkh(02e18f242c8b0b589bfffeac30e1baa80a60933a649c7fb0f1103e78fbf58aa0ed)")
448464
/// .expect("Valid segwitv0 descriptor");
449465
/// let pre_tap_desc = desc.into_pre_taproot_desc().expect("Wsh is pre taproot");
450-
///
451-
/// // Now the script code and explicit script no longer fail on longer fail
452-
/// // on PreTaprootDescriptor using PreTaprootDescriptorTrait
453-
/// let script_code = pre_tap_desc.script_code();
454-
/// assert_eq!(script_code.to_string(),
455-
/// "Script(OP_DUP OP_HASH160 OP_PUSHBYTES_20 62107d047e8818b594303fe0657388cc4fc8771f OP_EQUALVERIFY OP_CHECKSIG)"
456-
/// );
457466
/// ```
458467
///
459468
/// # Errors
@@ -618,25 +627,6 @@ impl<Pk: MiniscriptKey> DescriptorTrait<Pk> for Descriptor<Pk> {
618627
Descriptor::Tr(ref tr) => tr.max_satisfaction_weight(),
619628
}
620629
}
621-
622-
/// Get the `scriptCode` of a transaction output.
623-
///
624-
/// The `scriptCode` is the Script of the previous transaction output being serialized in the
625-
/// sighash when evaluating a `CHECKSIG` & co. OP code.
626-
/// Returns Error for Tr descriptors
627-
fn script_code(&self) -> Result<Script, Error>
628-
where
629-
Pk: ToPublicKey,
630-
{
631-
match *self {
632-
Descriptor::Bare(ref bare) => bare.script_code(),
633-
Descriptor::Pkh(ref pkh) => pkh.script_code(),
634-
Descriptor::Wpkh(ref wpkh) => wpkh.script_code(),
635-
Descriptor::Wsh(ref wsh) => wsh.script_code(),
636-
Descriptor::Sh(ref sh) => sh.script_code(),
637-
Descriptor::Tr(ref tr) => tr.script_code(),
638-
}
639-
}
640630
}
641631

642632
impl<Pk: MiniscriptKey> ForEachKey<Pk> for Descriptor<Pk> {

src/descriptor/pretaproot.rs

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -124,24 +124,6 @@ impl<Pk: MiniscriptKey> DescriptorTrait<Pk> for PreTaprootDescriptor<Pk> {
124124
PreTaprootDescriptor::Sh(ref sh) => sh.max_satisfaction_weight(),
125125
}
126126
}
127-
128-
/// Get the `scriptCode` of a transaction output.
129-
///
130-
/// The `scriptCode` is the Script of the previous transaction output being serialized in the
131-
/// sighash when evaluating a `CHECKSIG` & co. OP code.
132-
/// Returns Error for Tr descriptors
133-
fn script_code(&self) -> Result<Script, Error>
134-
where
135-
Pk: ToPublicKey,
136-
{
137-
match *self {
138-
PreTaprootDescriptor::Bare(ref bare) => bare.script_code(),
139-
PreTaprootDescriptor::Pkh(ref pkh) => pkh.script_code(),
140-
PreTaprootDescriptor::Wpkh(ref wpkh) => wpkh.script_code(),
141-
PreTaprootDescriptor::Wsh(ref wsh) => wsh.script_code(),
142-
PreTaprootDescriptor::Sh(ref sh) => sh.script_code(),
143-
}
144-
}
145127
}
146128

147129
impl<Pk> expression::FromTree for PreTaprootDescriptor<Pk>
@@ -207,28 +189,16 @@ serde_string_impl_pk!(PreTaprootDescriptor, "a pre-taproot script descriptor");
207189

208190
// Have the trait in a separate module to avoid conflicts
209191
pub(crate) mod traits {
210-
use bitcoin::Script;
211-
212192
use crate::{
213193
descriptor::{Pkh, Sh, Wpkh, Wsh},
214-
DescriptorTrait, MiniscriptKey, ToPublicKey,
194+
DescriptorTrait, MiniscriptKey,
215195
};
216196

217197
use super::PreTaprootDescriptor;
218198

219199
/// A general trait for Pre taproot bitcoin descriptor.
220200
/// Similar to [`DescriptorTrait`], but `explicit_script` and `script_code` methods cannot fail
221-
pub trait PreTaprootDescriptorTrait<Pk: MiniscriptKey>: DescriptorTrait<Pk> {
222-
/// Same as [`DescriptorTrait::script_code`], but a non failing version.
223-
/// All PreTaproot descriptors have a script code
224-
fn script_code(&self) -> Script
225-
where
226-
Pk: ToPublicKey,
227-
{
228-
<Self as DescriptorTrait<Pk>>::script_code(&self)
229-
.expect("Pre taproot descriptor have non-failing script code")
230-
}
231-
}
201+
pub trait PreTaprootDescriptorTrait<Pk: MiniscriptKey>: DescriptorTrait<Pk> {}
232202

233203
impl<Pk: MiniscriptKey> PreTaprootDescriptorTrait<Pk> for Pkh<Pk> {}
234204

src/descriptor/segwitv0.rs

Lines changed: 18 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use crate::{
3131

3232
use super::{
3333
checksum::{desc_checksum, verify_checksum},
34-
DescriptorTrait, ExplicitScript, SortedMultiVec, ToAddress,
34+
DescriptorTrait, ExplicitScript, ScriptCode, SortedMultiVec, ToAddress,
3535
};
3636
/// A Segwitv0 wsh descriptor
3737
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
@@ -78,15 +78,6 @@ impl<Pk: MiniscriptKey> Wsh<Pk> {
7878
}
7979
}
8080

81-
impl<Pk: MiniscriptKey + ToPublicKey> Wsh<Pk> {
82-
/// Obtains the pre bip-340 signature script code for this descriptor.
83-
/// Called by [`DescriptorTrait::script_code`] for this descriptor.
84-
/// Equivalent to `self.inner_script`.
85-
pub fn ecdsa_sighash_script_code(&self) -> Script {
86-
self.explicit_script()
87-
}
88-
}
89-
9081
/// Wsh Inner
9182
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
9283
pub enum WshInner<Pk: MiniscriptKey> {
@@ -238,13 +229,6 @@ impl<Pk: MiniscriptKey> DescriptorTrait<Pk> for Wsh<Pk> {
238229
varint_len(max_sat_elems) +
239230
max_sat_size)
240231
}
241-
242-
fn script_code(&self) -> Result<Script, Error>
243-
where
244-
Pk: ToPublicKey,
245-
{
246-
Ok(self.ecdsa_sighash_script_code())
247-
}
248232
}
249233

250234
impl<Pk: MiniscriptKey + ToPublicKey> ToAddress<Pk> for Wsh<Pk> {
@@ -265,6 +249,12 @@ impl<Pk: MiniscriptKey + ToPublicKey> ExplicitScript<Pk> for Wsh<Pk> {
265249
}
266250
}
267251

252+
impl<Pk: MiniscriptKey + ToPublicKey> ScriptCode<Pk> for Wsh<Pk> {
253+
fn script_code(&self) -> Script {
254+
self.explicit_script()
255+
}
256+
}
257+
268258
impl<Pk: MiniscriptKey> ForEachKey<Pk> for Wsh<Pk> {
269259
fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, pred: F) -> bool
270260
where
@@ -339,19 +329,6 @@ impl<Pk: MiniscriptKey> Wpkh<Pk> {
339329
}
340330
}
341331

342-
impl<Pk: MiniscriptKey + ToPublicKey> Wpkh<Pk> {
343-
/// Obtains the pre bip-340 signature script code for this descriptor.
344-
/// Called by [`DescriptorTrait::script_code`] for this descriptor.
345-
pub fn ecdsa_sighash_script_code(&self) -> Script {
346-
// For SegWit outputs, it is defined by bip-0143 (quoted below) and is different from
347-
// the previous txo's scriptPubKey.
348-
// The item 5:
349-
// - For P2WPKH witness program, the scriptCode is `0x1976a914{20-byte-pubkey-hash}88ac`.
350-
let addr = Address::p2pkh(&self.pk.to_public_key(), Network::Bitcoin);
351-
addr.script_pubkey()
352-
}
353-
}
354-
355332
impl<Pk: MiniscriptKey> fmt::Debug for Wpkh<Pk> {
356333
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
357334
write!(f, "wpkh({:?})", self.pk)
@@ -464,13 +441,6 @@ impl<Pk: MiniscriptKey> DescriptorTrait<Pk> for Wpkh<Pk> {
464441
fn max_satisfaction_weight(&self) -> Result<usize, Error> {
465442
Ok(4 + 1 + 73 + Segwitv0::pk_len(&self.pk))
466443
}
467-
468-
fn script_code(&self) -> Result<Script, Error>
469-
where
470-
Pk: ToPublicKey,
471-
{
472-
Ok(self.ecdsa_sighash_script_code())
473-
}
474444
}
475445

476446
impl<Pk: MiniscriptKey + ToPublicKey> ToAddress<Pk> for Wpkh<Pk> {
@@ -489,6 +459,17 @@ impl<Pk: MiniscriptKey + ToPublicKey> ExplicitScript<Pk> for Wpkh<Pk> {
489459
}
490460
}
491461

462+
impl<Pk: MiniscriptKey + ToPublicKey> ScriptCode<Pk> for Wpkh<Pk> {
463+
fn script_code(&self) -> Script {
464+
// For SegWit outputs, it is defined by bip-0143 (quoted below) and is different from
465+
// the previous txo's scriptPubKey.
466+
// The item 5:
467+
// - For P2WPKH witness program, the scriptCode is `0x1976a914{20-byte-pubkey-hash}88ac`.
468+
let addr = Address::p2pkh(&self.pk.to_public_key(), Network::Bitcoin);
469+
addr.script_pubkey()
470+
}
471+
}
472+
492473
impl<Pk: MiniscriptKey> ForEachKey<Pk> for Wpkh<Pk> {
493474
fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool
494475
where

0 commit comments

Comments
 (0)