Skip to content

Commit a730990

Browse files
committed
refactor Descriptor to be parameterized by Extension, not ExtParam
It was confusing to have `Descriptor` parameterized by `ExtParam`; it forced all descriptors to have the `CovenantExt` extension which will prevent any alternate extensions (eg Simplicity) and also made the `Extension` trait redundant. It also made the `NoExt` struct useless even though you were able to construct a `Descriptor<Pk, NoExt>` and do one or two things with it. This is very confusing. There was also confusion in the codebase in multiple places where extensions and extension parameters were confused. This commit introduces the ExtParamTranslator and TranslateExtParam traits to handle translation of the parameters; then it introduces some helper implementations to make this more ergonomic. It should now be actually possible to use descriptors without any extensions, which will facilitate Simplicity, infalible conversions to rust-miniscript structures, and hopefully let people figure out how to use the traits in this library without immediately being swallowed by an impossible maze of traits. BTW sorry for the huge diff on this commit. Everything was intertwined and I had to change everything at once to get it to compile. It should be less intertwined now so that future changes won't be so bad.
1 parent 3c64411 commit a730990

File tree

24 files changed

+206
-283
lines changed

24 files changed

+206
-283
lines changed

src/descriptor/blinded.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use elements::{self, Script};
2525
use super::checksum::{desc_checksum, strip_checksum, verify_checksum};
2626
use super::{Descriptor, TranslatePk};
2727
use crate::expression::{self, FromTree};
28-
use crate::extensions::CovExtArgs;
28+
use crate::extensions::{CovenantExt, CovExtArgs};
2929
use crate::policy::{semantic, Liftable};
3030
use crate::{Error, MiniscriptKey, Satisfier, ToPublicKey, Translator};
3131

@@ -40,12 +40,12 @@ pub struct Blinded<Pk: MiniscriptKey> {
4040
/// permitted at the root level.
4141
///
4242
/// TODO: Add blinding support to descriptor extensions
43-
desc: Descriptor<Pk, CovExtArgs>,
43+
desc: Descriptor<Pk, CovenantExt<CovExtArgs>>,
4444
}
4545

4646
impl<Pk: MiniscriptKey> Blinded<Pk> {
4747
/// Create a new blinded descriptor from a descriptor and blinder
48-
pub fn new(blinder: Pk, desc: Descriptor<Pk, CovExtArgs>) -> Self {
48+
pub fn new(blinder: Pk, desc: Descriptor<Pk, CovenantExt<CovExtArgs>>) -> Self {
4949
Self { blinder, desc }
5050
}
5151

@@ -55,12 +55,12 @@ impl<Pk: MiniscriptKey> Blinded<Pk> {
5555
}
5656

5757
/// get the unblinded descriptor
58-
pub fn as_unblinded(&self) -> &Descriptor<Pk, CovExtArgs> {
58+
pub fn as_unblinded(&self) -> &Descriptor<Pk, CovenantExt<CovExtArgs>> {
5959
&self.desc
6060
}
6161

6262
/// get the unblinded descriptor
63-
pub fn into_unblinded(self) -> Descriptor<Pk, CovExtArgs> {
63+
pub fn into_unblinded(self) -> Descriptor<Pk, CovenantExt<CovExtArgs>> {
6464
self.desc
6565
}
6666
}
@@ -92,7 +92,7 @@ impl_from_tree!(
9292
fn from_tree(top: &expression::Tree<'_>) -> Result<Self, Error> {
9393
if top.name == "blinded" && top.args.len() == 2 {
9494
let blinder = expression::terminal(&top.args[0], |pk| Pk::from_str(pk))?;
95-
let desc = Descriptor::<Pk, CovExtArgs>::from_tree(&top.args[1])?;
95+
let desc = Descriptor::<Pk, CovenantExt<CovExtArgs>>::from_tree(&top.args[1])?;
9696
if top.args[1].name == "blinded" {
9797
return Err(Error::BadDescriptor(
9898
"Blinding only permitted at root level".to_string(),

src/descriptor/csfs_cov/cov.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ use super::super::checksum::{desc_checksum, verify_checksum};
5151
use super::super::ELMTS_STR;
5252
use super::{CovError, CovOperations};
5353
use crate::expression::{self, FromTree};
54-
use crate::extensions::{ExtParam, ParseableExt};
54+
use crate::extensions::ParseableExt;
5555
use crate::miniscript::lex::{lex, Token as Tk, TokenIter};
5656
use crate::miniscript::limits::{
5757
MAX_OPS_PER_SCRIPT, MAX_SCRIPT_SIZE, MAX_STANDARD_P2WSH_SCRIPT_SIZE,
@@ -485,20 +485,18 @@ where
485485
}
486486
}
487487

488-
impl<Pk, Ext, ExtQ, PArg, QArg> TranslateExt<Ext, ExtQ, PArg, QArg> for LegacyCSFSCov<Pk, Ext>
488+
impl<Pk, Ext, ExtQ> TranslateExt<Ext, ExtQ> for LegacyCSFSCov<Pk, Ext>
489489
where
490490
Pk: MiniscriptKey,
491491
Ext: Extension,
492492
ExtQ: Extension,
493-
Ext: TranslateExt<Ext, ExtQ, PArg, QArg, Output = ExtQ>,
494-
PArg: ExtParam,
495-
QArg: ExtParam,
493+
Ext: TranslateExt<Ext, ExtQ, Output = ExtQ>,
496494
{
497495
type Output = LegacyCSFSCov<Pk, ExtQ>;
498496

499497
fn translate_ext<T, E>(&self, translator: &mut T) -> Result<Self::Output, E>
500498
where
501-
T: ExtTranslator<PArg, QArg, E>,
499+
T: ExtTranslator<Ext, ExtQ, E>,
502500
{
503501
Ok(LegacyCSFSCov {
504502
pk: self.pk.clone(),

src/descriptor/csfs_cov/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ mod tests {
182182
}
183183

184184
fn _satisfy_and_interpret(
185-
desc: Descriptor<bitcoin::PublicKey, CovExtArgs>,
185+
desc: Descriptor<bitcoin::PublicKey, CovenantExt<CovExtArgs>>,
186186
cov_sk: secp256k1_zkp::SecretKey,
187187
) -> Result<(), Error> {
188188
assert_eq!(desc.desc_type(), DescriptorType::Cov);

src/descriptor/mod.rs

Lines changed: 41 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use self::checksum::verify_checksum;
4040
use crate::extensions::{CovExtArgs, ExtParam, NoExtParam};
4141
use crate::miniscript::{Legacy, Miniscript, Segwitv0};
4242
use crate::{
43-
expression, miniscript, BareCtx, CovenantExt, Error, ExtTranslator, ForEach, ForEachKey,
43+
expression, miniscript, BareCtx, CovenantExt, Error, Extension, ExtTranslator, ForEach, ForEachKey,
4444
MiniscriptKey, NoExt, Satisfier, ToPublicKey, TranslateExt, TranslatePk, Translator,
4545
};
4646

@@ -202,7 +202,7 @@ impl DescriptorInfo {
202202
/// of the type [DescriptorSecretKey]. If the descriptor contains secret, users
203203
/// should use the method [DescriptorPublicKey::parse_descriptor] to obtain the
204204
/// Descriptor and a secret key to public key mapping
205-
pub fn from_desc_str<T: ExtParam>(s: &str) -> Result<Self, Error> {
205+
pub fn from_desc_str<T: Extension>(s: &str) -> Result<Self, Error> {
206206
// Parse as a string descriptor
207207
let descriptor = Descriptor::<String, T>::from_str(s)?;
208208
let has_secret = descriptor.for_any_key(|pk| match pk {
@@ -225,7 +225,7 @@ impl DescriptorInfo {
225225

226226
/// Script descriptor
227227
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
228-
pub enum Descriptor<Pk: MiniscriptKey, T: ExtParam = CovExtArgs> {
228+
pub enum Descriptor<Pk: MiniscriptKey, T: Extension = CovenantExt<CovExtArgs>> {
229229
/// A raw scriptpubkey (including pay-to-pubkey) under Legacy context
230230
Bare(Bare<Pk>),
231231
/// Pay-to-PubKey-Hash
@@ -239,57 +239,57 @@ pub enum Descriptor<Pk: MiniscriptKey, T: ExtParam = CovExtArgs> {
239239
/// Pay-to-Taproot
240240
Tr(Tr<Pk, NoExt>),
241241
/// Pay-to-Taproot
242-
TrExt(Tr<Pk, CovenantExt<T>>),
242+
TrExt(Tr<Pk, T>),
243243
/// Covenant descriptor with all known extensions
244244
/// Downstream implementations of extensions should implement directly use descriptor API
245-
LegacyCSFSCov(LegacyCSFSCov<Pk, CovenantExt<T>>),
245+
LegacyCSFSCov(LegacyCSFSCov<Pk, T>),
246246
}
247247

248-
impl<Pk: MiniscriptKey> From<Bare<Pk>> for Descriptor<Pk, NoExtParam> {
248+
impl<Pk: MiniscriptKey> From<Bare<Pk>> for Descriptor<Pk, CovenantExt<NoExtParam>> {
249249
#[inline]
250250
fn from(inner: Bare<Pk>) -> Self {
251251
Descriptor::Bare(inner)
252252
}
253253
}
254254

255-
impl<Pk: MiniscriptKey> From<Pkh<Pk>> for Descriptor<Pk, NoExtParam> {
255+
impl<Pk: MiniscriptKey> From<Pkh<Pk>> for Descriptor<Pk, CovenantExt<NoExtParam>> {
256256
#[inline]
257257
fn from(inner: Pkh<Pk>) -> Self {
258258
Descriptor::Pkh(inner)
259259
}
260260
}
261261

262-
impl<Pk: MiniscriptKey> From<Wpkh<Pk>> for Descriptor<Pk, NoExtParam> {
262+
impl<Pk: MiniscriptKey> From<Wpkh<Pk>> for Descriptor<Pk, CovenantExt<NoExtParam>> {
263263
#[inline]
264264
fn from(inner: Wpkh<Pk>) -> Self {
265265
Descriptor::Wpkh(inner)
266266
}
267267
}
268268

269-
impl<Pk: MiniscriptKey> From<Sh<Pk>> for Descriptor<Pk, NoExtParam> {
269+
impl<Pk: MiniscriptKey> From<Sh<Pk>> for Descriptor<Pk, CovenantExt<NoExtParam>> {
270270
#[inline]
271271
fn from(inner: Sh<Pk>) -> Self {
272272
Descriptor::Sh(inner)
273273
}
274274
}
275275

276-
impl<Pk: MiniscriptKey> From<Wsh<Pk>> for Descriptor<Pk, NoExtParam> {
276+
impl<Pk: MiniscriptKey> From<Wsh<Pk>> for Descriptor<Pk, CovenantExt<NoExtParam>> {
277277
#[inline]
278278
fn from(inner: Wsh<Pk>) -> Self {
279279
Descriptor::Wsh(inner)
280280
}
281281
}
282282

283-
impl<Pk: MiniscriptKey> From<Tr<Pk, NoExt>> for Descriptor<Pk, NoExtParam> {
283+
impl<Pk: MiniscriptKey> From<Tr<Pk, NoExt>> for Descriptor<Pk, CovenantExt<NoExtParam>> {
284284
#[inline]
285285
fn from(inner: Tr<Pk, NoExt>) -> Self {
286286
Descriptor::Tr(inner)
287287
}
288288
}
289289

290-
impl<Pk: MiniscriptKey, T: ExtParam> From<LegacyCSFSCov<Pk, CovenantExt<T>>> for Descriptor<Pk, T> {
290+
impl<Pk: MiniscriptKey, Arg: ExtParam> From<LegacyCSFSCov<Pk, CovenantExt<Arg>>> for Descriptor<Pk, CovenantExt<Arg>> {
291291
#[inline]
292-
fn from(inner: LegacyCSFSCov<Pk, CovenantExt<T>>) -> Self {
292+
fn from(inner: LegacyCSFSCov<Pk, CovenantExt<Arg>>) -> Self {
293293
Descriptor::LegacyCSFSCov(inner)
294294
}
295295
}
@@ -313,7 +313,7 @@ impl DescriptorType {
313313
}
314314
}
315315

316-
impl<Pk: MiniscriptKey, T: ExtParam> Descriptor<Pk, T> {
316+
impl<Pk: MiniscriptKey, Arg: ExtParam> Descriptor<Pk, CovenantExt<Arg>> {
317317
// Keys
318318

319319
/// Create a new pk descriptor
@@ -419,7 +419,7 @@ impl<Pk: MiniscriptKey, T: ExtParam> Descriptor<Pk, T> {
419419
/// Errors when miniscript exceeds resource limits under Tap context
420420
pub fn new_tr_ext(
421421
key: Pk,
422-
script: Option<tr::TapTree<Pk, CovenantExt<T>>>,
422+
script: Option<tr::TapTree<Pk, CovenantExt<Arg>>>,
423423
) -> Result<Self, Error> {
424424
Ok(Descriptor::TrExt(Tr::new(key, script)?))
425425
}
@@ -499,19 +499,19 @@ impl<Pk: MiniscriptKey, T: ExtParam> Descriptor<Pk, T> {
499499
}
500500
}
501501

502-
impl<Pk: MiniscriptKey, T: ExtParam> Descriptor<Pk, T> {
502+
impl<Pk: MiniscriptKey, Arg: ExtParam> Descriptor<Pk, CovenantExt<Arg>> {
503503
/// Create a new covenant descriptor
504504
// All extensions are supported in wsh descriptor
505505
pub fn new_cov_wsh(
506506
pk: Pk,
507-
ms: Miniscript<Pk, Segwitv0, CovenantExt<T>>,
507+
ms: Miniscript<Pk, Segwitv0, CovenantExt<Arg>>,
508508
) -> Result<Self, Error> {
509509
let cov = LegacyCSFSCov::new(pk, ms)?;
510510
Ok(Descriptor::LegacyCSFSCov(cov))
511511
}
512512

513513
/// Tries to convert descriptor as a covenant descriptor
514-
pub fn as_cov(&self) -> Result<&LegacyCSFSCov<Pk, CovenantExt<T>>, Error> {
514+
pub fn as_cov(&self) -> Result<&LegacyCSFSCov<Pk, CovenantExt<Arg>>, Error> {
515515
if let Descriptor::LegacyCSFSCov(cov) = self {
516516
Ok(cov)
517517
} else {
@@ -520,7 +520,7 @@ impl<Pk: MiniscriptKey, T: ExtParam> Descriptor<Pk, T> {
520520
}
521521
}
522522

523-
impl<Pk: MiniscriptKey + ToPublicKey> Descriptor<Pk, CovExtArgs> {
523+
impl<Pk: MiniscriptKey + ToPublicKey> Descriptor<Pk, CovenantExt<CovExtArgs>> {
524524
///
525525
/// Obtains the blinded address for this descriptor
526526
///
@@ -693,13 +693,13 @@ impl<Pk: MiniscriptKey + ToPublicKey> Descriptor<Pk, CovExtArgs> {
693693
}
694694
}
695695

696-
impl<P, Q, Arg> TranslatePk<P, Q> for Descriptor<P, Arg>
696+
impl<P, Q, Ext> TranslatePk<P, Q> for Descriptor<P, Ext>
697697
where
698698
P: MiniscriptKey,
699699
Q: MiniscriptKey,
700-
Arg: ExtParam,
700+
Ext: Extension,
701701
{
702-
type Output = Descriptor<Q, Arg>;
702+
type Output = Descriptor<Q, Ext>;
703703

704704
/// Converts a descriptor using abstract keys to one using specific keys.
705705
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, E>
@@ -720,22 +720,20 @@ where
720720
}
721721
}
722722

723-
impl<PArg, QArg, Pk> TranslateExt<CovenantExt<PArg>, CovenantExt<QArg>, PArg, QArg>
724-
for Descriptor<Pk, PArg>
723+
impl<PExt, QExt, Pk> TranslateExt<PExt, QExt>
724+
for Descriptor<Pk, PExt>
725725
where
726-
PArg: ExtParam,
727-
QArg: ExtParam,
726+
PExt: Extension + TranslateExt<PExt, QExt, Output = QExt>,
727+
QExt: Extension,
728728
Pk: MiniscriptKey,
729-
// PExt: TranslateExt<PExt, QExt, PArg, QArg, Output = QExt>,
730-
// Tr<Pk, CovenantExt<PArg>>: TranslateExt<PExt, QExt, PArg, QArg,>
731729
{
732-
type Output = Descriptor<Pk, QArg>;
730+
type Output = Descriptor<Pk, QExt>;
733731

734732
/// Converts a descriptor using abstract keys to one using specific keys.
735733
#[rustfmt::skip]
736734
fn translate_ext<T, E>(&self, t: &mut T) -> Result<Self::Output, E>
737735
where
738-
T: ExtTranslator<PArg, QArg, E>,
736+
T: ExtTranslator<PExt, QExt, E>,
739737
{
740738
let desc = match *self {
741739
Descriptor::Bare(ref bare) => Descriptor::Bare(bare.clone()),
@@ -745,10 +743,10 @@ where
745743
Descriptor::Wsh(ref wsh) => Descriptor::Wsh(wsh.clone()),
746744
Descriptor::Tr(ref tr) => Descriptor::Tr(tr.clone()),
747745
Descriptor::TrExt(ref tr) => Descriptor::TrExt(
748-
TranslateExt::<CovenantExt<PArg>, CovenantExt<QArg>, _, _>::translate_ext(tr, t)?,
746+
TranslateExt::<PExt, QExt>::translate_ext(tr, t)?,
749747
),
750748
Descriptor::LegacyCSFSCov(ref cov) => {
751-
Descriptor::LegacyCSFSCov(TranslateExt::<CovenantExt<PArg>, CovenantExt<QArg>, _, _>::translate_ext(
749+
Descriptor::LegacyCSFSCov(TranslateExt::<PExt, QExt>::translate_ext(
752750
cov, t,
753751
)?)
754752
}
@@ -757,7 +755,7 @@ where
757755
}
758756
}
759757

760-
impl<Pk: MiniscriptKey, T: ExtParam> ForEachKey<Pk> for Descriptor<Pk, T> {
758+
impl<Pk: MiniscriptKey, T: Extension> ForEachKey<Pk> for Descriptor<Pk, T> {
761759
fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, pred: F) -> bool
762760
where
763761
Pk: 'a,
@@ -962,7 +960,7 @@ impl Descriptor<DescriptorPublicKey> {
962960
}
963961
}
964962

965-
impl Descriptor<DescriptorPublicKey, CovExtArgs> {
963+
impl Descriptor<DescriptorPublicKey, CovenantExt<CovExtArgs>> {
966964
/// Utility method for deriving the descriptor at each index in a range to find one matching
967965
/// `script_pubkey`.
968966
///
@@ -975,7 +973,7 @@ impl Descriptor<DescriptorPublicKey, CovExtArgs> {
975973
secp: &secp256k1_zkp::Secp256k1<C>,
976974
script_pubkey: &Script,
977975
range: Range<u32>,
978-
) -> Result<Option<(u32, Descriptor<bitcoin::PublicKey, CovExtArgs>)>, ConversionError> {
976+
) -> Result<Option<(u32, Descriptor<bitcoin::PublicKey, CovenantExt<CovExtArgs>>)>, ConversionError> {
979977
let range = if self.is_deriveable() { range } else { 0..1 };
980978

981979
for i in range {
@@ -991,7 +989,7 @@ impl Descriptor<DescriptorPublicKey, CovExtArgs> {
991989
}
992990

993991
impl_from_tree!(
994-
;T; ExtParam,
992+
;T; Extension,
995993
Descriptor<Pk, T>,
996994
/// Parse an expression tree into a descriptor.
997995
fn from_tree(top: &expression::Tree) -> Result<Descriptor<Pk, T>, Error> {
@@ -1008,7 +1006,7 @@ impl_from_tree!(
10081006
);
10091007

10101008
impl_from_str!(
1011-
;T; ExtParam,
1009+
;T; Extension,
10121010
Descriptor<Pk, T>,
10131011
type Err = Error;,
10141012
fn from_str(s: &str) -> Result<Descriptor<Pk, T>, Error> {
@@ -1026,7 +1024,7 @@ impl_from_str!(
10261024
Ok(tr) => Ok(Descriptor::Tr(tr)),
10271025
Err(_) => {
10281026
// Try parsing with extensions
1029-
let tr = Tr::<Pk, CovenantExt<T>>::from_str(s)?;
1027+
let tr = Tr::<Pk, T>::from_str(s)?;
10301028
Ok(Descriptor::TrExt(tr))
10311029
}
10321030
}
@@ -1038,7 +1036,7 @@ impl_from_str!(
10381036
}
10391037
);
10401038

1041-
impl<Pk: MiniscriptKey, T: ExtParam> fmt::Debug for Descriptor<Pk, T> {
1039+
impl<Pk: MiniscriptKey, T: Extension> fmt::Debug for Descriptor<Pk, T> {
10421040
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
10431041
match *self {
10441042
Descriptor::Bare(ref sub) => write!(f, "{:?}", sub),
@@ -1053,7 +1051,7 @@ impl<Pk: MiniscriptKey, T: ExtParam> fmt::Debug for Descriptor<Pk, T> {
10531051
}
10541052
}
10551053

1056-
impl<Pk: MiniscriptKey, T: ExtParam> fmt::Display for Descriptor<Pk, T> {
1054+
impl<Pk: MiniscriptKey, T: Extension> fmt::Display for Descriptor<Pk, T> {
10571055
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
10581056
match *self {
10591057
Descriptor::Bare(ref sub) => write!(f, "{}", sub),
@@ -1068,7 +1066,7 @@ impl<Pk: MiniscriptKey, T: ExtParam> fmt::Display for Descriptor<Pk, T> {
10681066
}
10691067
}
10701068

1071-
serde_string_impl_pk!(Descriptor, "a script descriptor", T; ExtParam);
1069+
serde_string_impl_pk!(Descriptor, "a script descriptor", T; Extension);
10721070

10731071
#[cfg(test)]
10741072
mod tests {
@@ -1095,7 +1093,7 @@ mod tests {
10951093
use crate::policy;
10961094
use crate::{hex_script, Descriptor, DummyKey, Error, Miniscript, Satisfier};
10971095

1098-
type StdDescriptor = Descriptor<PublicKey, CovExtArgs>;
1096+
type StdDescriptor = Descriptor<PublicKey, CovenantExt<CovExtArgs>>;
10991097
const TEST_PK: &'static str =
11001098
"elpk(020000000000000000000000000000000000000000000000000000000000000002)";
11011099

@@ -1910,7 +1908,7 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))";
19101908
let res_policy: policy::concrete::Policy<DescriptorPublicKey> =
19111909
res_descriptor_str.parse().unwrap();
19121910
let res_descriptor =
1913-
Descriptor::<DescriptorPublicKey, NoExtParam>::new_sh(res_policy.compile().unwrap())
1911+
Descriptor::<DescriptorPublicKey, CovenantExt<NoExtParam>>::new_sh(res_policy.compile().unwrap())
19141912
.unwrap();
19151913

19161914
assert_eq!(res_descriptor.to_string(), derived_descriptor.to_string());

0 commit comments

Comments
 (0)