Skip to content

Commit ad3d736

Browse files
committed
Merge #493: update TranslatePk again
b90cdda Change try_into_translator_err to expect_translator_err (sanket1729) be07a9c Update TranslatePk again (sanket1729) ee8de9a Cleanly check validity rules for DescriptorKeys (sanket1729) fa2e8b4 Cleanup Miniscript constructors (sanket1729) Pull request description: This PR has lot of cleanups that I had planned but did not have time for a long time. - All places now use constructors that do invariant checking on the struct being created. - Translate* APIs had a soundness bug you could create uncompressed keys in segwit descriptors etc. ACKs for top commit: apoelstra: ACK b90cdda Tree-SHA512: d1c7001650b55c018d6e395628cb3cb8e5d15540c24b696946d370202e6ccc82b376b7f18c1138fdbd83a550fef0e39dc8b44fd670019dc4854b87a67cdc41c7
2 parents be27637 + b90cdda commit ad3d736

File tree

14 files changed

+353
-230
lines changed

14 files changed

+353
-230
lines changed

bitcoind-tests/tests/setup/test_util.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,10 @@ pub fn parse_test_desc(
279279
let desc = subs_hash_frag(desc, pubdata);
280280
let desc = Descriptor::<String>::from_str(&desc)?;
281281
let mut translator = StrDescPubKeyTranslator(0, pubdata);
282-
let desc: Result<_, ()> = desc.translate_pk(&mut translator);
283-
Ok(desc.expect("Translate must succeed"))
282+
let desc = desc
283+
.translate_pk(&mut translator)
284+
.expect("Translation failed");
285+
Ok(desc)
284286
}
285287

286288
// substitute hash fragments in the string as the per rules

src/descriptor/bare.rs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ use bitcoin::{Address, Network, ScriptBuf};
1515

1616
use super::checksum::{self, verify_checksum};
1717
use crate::expression::{self, FromTree};
18-
use crate::miniscript::context::ScriptContext;
18+
use crate::miniscript::context::{ScriptContext, ScriptContextError};
1919
use crate::policy::{semantic, Liftable};
2020
use crate::prelude::*;
2121
use crate::util::{varint_len, witness_to_scriptsig};
2222
use crate::{
23-
BareCtx, Error, ForEachKey, Miniscript, MiniscriptKey, Satisfier, ToPublicKey, TranslatePk,
24-
Translator,
23+
BareCtx, Error, ForEachKey, Miniscript, MiniscriptKey, Satisfier, ToPublicKey, TranslateErr,
24+
TranslatePk, Translator,
2525
};
2626

2727
/// Create a Bare Descriptor. That is descriptor that is
@@ -188,11 +188,11 @@ where
188188
{
189189
type Output = Bare<Q>;
190190

191-
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, E>
191+
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Bare<Q>, TranslateErr<E>>
192192
where
193193
T: Translator<P, Q, E>,
194194
{
195-
Ok(Bare::new(self.ms.translate_pk(t)?).expect("Translation cannot fail inside Bare"))
195+
Ok(Bare::new(self.ms.translate_pk(t)?).map_err(TranslateErr::OuterError)?)
196196
}
197197
}
198198

@@ -205,9 +205,12 @@ pub struct Pkh<Pk: MiniscriptKey> {
205205

206206
impl<Pk: MiniscriptKey> Pkh<Pk> {
207207
/// Create a new Pkh descriptor
208-
pub fn new(pk: Pk) -> Self {
208+
pub fn new(pk: Pk) -> Result<Self, ScriptContextError> {
209209
// do the top-level checks
210-
Self { pk }
210+
match BareCtx::check_pk(&pk) {
211+
Ok(()) => Ok(Pkh { pk }),
212+
Err(e) => Err(e),
213+
}
211214
}
212215

213216
/// Get a reference to the inner key
@@ -336,7 +339,7 @@ impl_from_tree!(
336339
if top.name == "pkh" && top.args.len() == 1 {
337340
Ok(Pkh::new(expression::terminal(&top.args[0], |pk| {
338341
Pk::from_str(pk)
339-
})?))
342+
})?)?)
340343
} else {
341344
Err(Error::Unexpected(format!(
342345
"{}({} args) while parsing pkh descriptor",
@@ -370,10 +373,14 @@ where
370373
{
371374
type Output = Pkh<Q>;
372375

373-
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, E>
376+
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, TranslateErr<E>>
374377
where
375378
T: Translator<P, Q, E>,
376379
{
377-
Ok(Pkh::new(t.pk(&self.pk)?))
380+
let res = Pkh::new(t.pk(&self.pk)?);
381+
match res {
382+
Ok(pk) => Ok(pk),
383+
Err(e) => Err(TranslateErr::OuterError(Error::from(e))),
384+
}
378385
}
379386
}

src/descriptor/mod.rs

Lines changed: 70 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use crate::miniscript::{Legacy, Miniscript, Segwitv0};
2626
use crate::prelude::*;
2727
use crate::{
2828
expression, hash256, miniscript, BareCtx, Error, ForEachKey, MiniscriptKey, Satisfier,
29-
ToPublicKey, TranslatePk, Translator,
29+
ToPublicKey, TranslateErr, TranslatePk, Translator,
3030
};
3131

3232
mod bare;
@@ -177,8 +177,8 @@ impl<Pk: MiniscriptKey> Descriptor<Pk> {
177177
}
178178

179179
/// Create a new PkH descriptor
180-
pub fn new_pkh(pk: Pk) -> Self {
181-
Descriptor::Pkh(Pkh::new(pk))
180+
pub fn new_pkh(pk: Pk) -> Result<Self, Error> {
181+
Ok(Descriptor::Pkh(Pkh::new(pk)?))
182182
}
183183

184184
/// Create a new Wpkh descriptor
@@ -519,7 +519,7 @@ where
519519
type Output = Descriptor<Q>;
520520

521521
/// Converts a descriptor using abstract keys to one using specific keys.
522-
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, E>
522+
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, TranslateErr<E>>
523523
where
524524
T: Translator<P, Q, E>,
525525
{
@@ -582,6 +582,7 @@ impl Descriptor<DescriptorPublicKey> {
582582
translate_hash_clone!(DescriptorPublicKey, DescriptorPublicKey, ConversionError);
583583
}
584584
self.translate_pk(&mut Derivator(index))
585+
.map_err(|e| e.expect_translator_err("No Context errors while translating"))
585586
}
586587

587588
#[deprecated(note = "use at_derivation_index instead")]
@@ -694,9 +695,12 @@ impl Descriptor<DescriptorPublicKey> {
694695
}
695696

696697
let descriptor = Descriptor::<String>::from_str(s)?;
697-
let descriptor = descriptor
698-
.translate_pk(&mut keymap_pk)
699-
.map_err(|e| Error::Unexpected(e.to_string()))?;
698+
let descriptor = descriptor.translate_pk(&mut keymap_pk).map_err(|e| {
699+
Error::Unexpected(
700+
e.expect_translator_err("No Outer context errors")
701+
.to_string(),
702+
)
703+
})?;
700704

701705
Ok((descriptor, keymap_pk.0))
702706
}
@@ -823,49 +827,15 @@ impl Descriptor<DescriptorPublicKey> {
823827

824828
for (i, desc) in descriptors.iter_mut().enumerate() {
825829
let mut index_choser = IndexChoser(i);
826-
*desc = desc.translate_pk(&mut index_choser)?;
830+
*desc = desc
831+
.translate_pk(&mut index_choser)
832+
.map_err(|e| e.expect_translator_err("No Context errors possible"))?;
827833
}
828834

829835
Ok(descriptors)
830836
}
831837
}
832838

833-
impl<Pk: MiniscriptKey> Descriptor<Pk> {
834-
/// Whether this descriptor is a multipath descriptor that contains any 2 multipath keys
835-
/// with a different number of derivation paths.
836-
/// Such a descriptor is invalid according to BIP389.
837-
pub fn multipath_length_mismatch(&self) -> bool {
838-
// (Ab)use `for_each_key` to record the number of derivation paths a multipath key has.
839-
#[derive(PartialEq)]
840-
enum MultipathLenChecker {
841-
SinglePath,
842-
MultipathLen(usize),
843-
LenMismatch,
844-
}
845-
846-
let mut checker = MultipathLenChecker::SinglePath;
847-
self.for_each_key(|key| {
848-
match key.num_der_paths() {
849-
0 | 1 => {}
850-
n => match checker {
851-
MultipathLenChecker::SinglePath => {
852-
checker = MultipathLenChecker::MultipathLen(n);
853-
}
854-
MultipathLenChecker::MultipathLen(len) => {
855-
if len != n {
856-
checker = MultipathLenChecker::LenMismatch;
857-
}
858-
}
859-
MultipathLenChecker::LenMismatch => {}
860-
},
861-
}
862-
true
863-
});
864-
865-
checker == MultipathLenChecker::LenMismatch
866-
}
867-
}
868-
869839
impl Descriptor<DefiniteDescriptorKey> {
870840
/// Convert all the public keys in the descriptor to [`bitcoin::PublicKey`] by deriving them or
871841
/// otherwise converting them. All [`bitcoin::secp256k1::XOnlyPublicKey`]s are converted to by adding a
@@ -909,8 +879,11 @@ impl Descriptor<DefiniteDescriptorKey> {
909879
translate_hash_clone!(DefiniteDescriptorKey, bitcoin::PublicKey, ConversionError);
910880
}
911881

912-
let derived = self.translate_pk(&mut Derivator(secp))?;
913-
Ok(derived)
882+
let derived = self.translate_pk(&mut Derivator(secp));
883+
match derived {
884+
Ok(derived) => Ok(derived),
885+
Err(e) => Err(e.expect_translator_err("No Context errors when deriving keys")),
886+
}
914887
}
915888
}
916889

@@ -944,10 +917,6 @@ impl_from_str!(
944917
expression::FromTree::from_tree(&top)
945918
}?;
946919

947-
if desc.multipath_length_mismatch() {
948-
return Err(Error::MultipathDescLenMismatch);
949-
}
950-
951920
Ok(desc)
952921
}
953922
);
@@ -1297,7 +1266,7 @@ mod tests {
12971266
);
12981267
assert_eq!(bare.unsigned_script_sig(), bitcoin::ScriptBuf::new());
12991268

1300-
let pkh = Descriptor::new_pkh(pk);
1269+
let pkh = Descriptor::new_pkh(pk).unwrap();
13011270
pkh.satisfy(&mut txin, &satisfier).expect("satisfaction");
13021271
assert_eq!(
13031272
txin,
@@ -1992,7 +1961,6 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))";
19921961
// We can parse a multipath descriptors, and make it into separate single-path descriptors.
19931962
let desc = Descriptor::from_str("wsh(andor(pk(tpubDEN9WSToTyy9ZQfaYqSKfmVqmq1VVLNtYfj3Vkqh67et57eJ5sTKZQBkHqSwPUsoSskJeaYnPttHe2VrkCsKA27kUaN9SDc5zhqeLzKa1rr/0'/<7';8h;20>/*),older(10000),pk(tpubD8LYfn6njiA2inCoxwM7EuN3cuLVcaHAwLYeups13dpevd3nHLRdK9NdQksWXrhLQVxcUZRpnp5CkJ1FhE61WRAsHxDNAkvGkoQkAeWDYjV/8/4567/<0;1;987>/*)))").unwrap();
19941963
assert!(desc.is_multipath());
1995-
assert!(!desc.multipath_length_mismatch());
19961964
assert_eq!(desc.into_single_descriptors().unwrap(), vec![
19971965
Descriptor::from_str("wsh(andor(pk(tpubDEN9WSToTyy9ZQfaYqSKfmVqmq1VVLNtYfj3Vkqh67et57eJ5sTKZQBkHqSwPUsoSskJeaYnPttHe2VrkCsKA27kUaN9SDc5zhqeLzKa1rr/0'/7'/*),older(10000),pk(tpubD8LYfn6njiA2inCoxwM7EuN3cuLVcaHAwLYeups13dpevd3nHLRdK9NdQksWXrhLQVxcUZRpnp5CkJ1FhE61WRAsHxDNAkvGkoQkAeWDYjV/8/4567/0/*)))").unwrap(),
19981966
Descriptor::from_str("wsh(andor(pk(tpubDEN9WSToTyy9ZQfaYqSKfmVqmq1VVLNtYfj3Vkqh67et57eJ5sTKZQBkHqSwPUsoSskJeaYnPttHe2VrkCsKA27kUaN9SDc5zhqeLzKa1rr/0'/8h/*),older(10000),pk(tpubD8LYfn6njiA2inCoxwM7EuN3cuLVcaHAwLYeups13dpevd3nHLRdK9NdQksWXrhLQVxcUZRpnp5CkJ1FhE61WRAsHxDNAkvGkoQkAeWDYjV/8/4567/1/*)))").unwrap(),
@@ -2002,7 +1970,6 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))";
20021970
// Even if only one of the keys is multipath.
20031971
let desc = Descriptor::from_str("wsh(andor(pk(tpubDEN9WSToTyy9ZQfaYqSKfmVqmq1VVLNtYfj3Vkqh67et57eJ5sTKZQBkHqSwPUsoSskJeaYnPttHe2VrkCsKA27kUaN9SDc5zhqeLzKa1rr/0'/<0;1>/*),older(10000),pk(tpubD8LYfn6njiA2inCoxwM7EuN3cuLVcaHAwLYeups13dpevd3nHLRdK9NdQksWXrhLQVxcUZRpnp5CkJ1FhE61WRAsHxDNAkvGkoQkAeWDYjV/8/4567/*)))").unwrap();
20041972
assert!(desc.is_multipath());
2005-
assert!(!desc.multipath_length_mismatch());
20061973
assert_eq!(desc.into_single_descriptors().unwrap(), vec![
20071974
Descriptor::from_str("wsh(andor(pk(tpubDEN9WSToTyy9ZQfaYqSKfmVqmq1VVLNtYfj3Vkqh67et57eJ5sTKZQBkHqSwPUsoSskJeaYnPttHe2VrkCsKA27kUaN9SDc5zhqeLzKa1rr/0'/0/*),older(10000),pk(tpubD8LYfn6njiA2inCoxwM7EuN3cuLVcaHAwLYeups13dpevd3nHLRdK9NdQksWXrhLQVxcUZRpnp5CkJ1FhE61WRAsHxDNAkvGkoQkAeWDYjV/8/4567/*)))").unwrap(),
20081975
Descriptor::from_str("wsh(andor(pk(tpubDEN9WSToTyy9ZQfaYqSKfmVqmq1VVLNtYfj3Vkqh67et57eJ5sTKZQBkHqSwPUsoSskJeaYnPttHe2VrkCsKA27kUaN9SDc5zhqeLzKa1rr/0'/1/*),older(10000),pk(tpubD8LYfn6njiA2inCoxwM7EuN3cuLVcaHAwLYeups13dpevd3nHLRdK9NdQksWXrhLQVxcUZRpnp5CkJ1FhE61WRAsHxDNAkvGkoQkAeWDYjV/8/4567/*)))").unwrap(),
@@ -2011,7 +1978,6 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))";
20111978
// We can detect regular single-path descriptors.
20121979
let notmulti_desc = Descriptor::from_str("wsh(andor(pk(tpubDEN9WSToTyy9ZQfaYqSKfmVqmq1VVLNtYfj3Vkqh67et57eJ5sTKZQBkHqSwPUsoSskJeaYnPttHe2VrkCsKA27kUaN9SDc5zhqeLzKa1rr/0'/*),older(10000),pk(tpubD8LYfn6njiA2inCoxwM7EuN3cuLVcaHAwLYeups13dpevd3nHLRdK9NdQksWXrhLQVxcUZRpnp5CkJ1FhE61WRAsHxDNAkvGkoQkAeWDYjV/8/4567/*)))").unwrap();
20131980
assert!(!notmulti_desc.is_multipath());
2014-
assert!(!notmulti_desc.multipath_length_mismatch());
20151981
assert_eq!(
20161982
notmulti_desc.clone().into_single_descriptors().unwrap(),
20171983
vec![notmulti_desc]
@@ -2021,4 +1987,54 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))";
20211987
Descriptor::<DescriptorPublicKey>::from_str("wsh(andor(pk(tpubDEN9WSToTyy9ZQfaYqSKfmVqmq1VVLNtYfj3Vkqh67et57eJ5sTKZQBkHqSwPUsoSskJeaYnPttHe2VrkCsKA27kUaN9SDc5zhqeLzKa1rr/0'/<0;1>/*),older(10000),pk(tpubD8LYfn6njiA2inCoxwM7EuN3cuLVcaHAwLYeups13dpevd3nHLRdK9NdQksWXrhLQVxcUZRpnp5CkJ1FhE61WRAsHxDNAkvGkoQkAeWDYjV/8/<0;1;2;3;4>/*)))").unwrap_err();
20221988
Descriptor::<DescriptorPublicKey>::from_str("wsh(andor(pk(tpubDEN9WSToTyy9ZQfaYqSKfmVqmq1VVLNtYfj3Vkqh67et57eJ5sTKZQBkHqSwPUsoSskJeaYnPttHe2VrkCsKA27kUaN9SDc5zhqeLzKa1rr/0'/<0;1;2;3>/*),older(10000),pk(tpubD8LYfn6njiA2inCoxwM7EuN3cuLVcaHAwLYeups13dpevd3nHLRdK9NdQksWXrhLQVxcUZRpnp5CkJ1FhE61WRAsHxDNAkvGkoQkAeWDYjV/8/<0;1;2>/*)))").unwrap_err();
20231989
}
1990+
1991+
#[test]
1992+
fn test_context_pks() {
1993+
let comp_key = bitcoin::PublicKey::from_str(
1994+
"02015e4cb53458bf813db8c79968e76e10d13ed6426a23fa71c2f41ba021c2a7ab",
1995+
)
1996+
.unwrap();
1997+
let x_only_key = bitcoin::key::XOnlyPublicKey::from_str(
1998+
"015e4cb53458bf813db8c79968e76e10d13ed6426a23fa71c2f41ba021c2a7ab",
1999+
)
2000+
.unwrap();
2001+
let uncomp_key = bitcoin::PublicKey::from_str("04015e4cb53458bf813db8c79968e76e10d13ed6426a23fa71c2f41ba021c2a7ab0d46021e9e69ef061eb25eab41ae206187b2b05e829559df59d78319bd9267b4").unwrap();
2002+
2003+
type Desc = Descriptor<DescriptorPublicKey>;
2004+
2005+
// Legacy tests, x-only keys are not supported
2006+
Desc::from_str(&format!("sh(pk({}))", comp_key)).unwrap();
2007+
Desc::from_str(&format!("sh(pk({}))", uncomp_key)).unwrap();
2008+
Desc::from_str(&format!("sh(pk({}))", x_only_key)).unwrap_err();
2009+
2010+
// bare tests, x-only keys not supported
2011+
Desc::from_str(&format!("pk({})", comp_key)).unwrap();
2012+
Desc::from_str(&format!("pk({})", uncomp_key)).unwrap();
2013+
Desc::from_str(&format!("pk({})", x_only_key)).unwrap_err();
2014+
2015+
// pkh tests, x-only keys not supported
2016+
Desc::from_str(&format!("pkh({})", comp_key)).unwrap();
2017+
Desc::from_str(&format!("pkh({})", uncomp_key)).unwrap();
2018+
Desc::from_str(&format!("pkh({})", x_only_key)).unwrap_err();
2019+
2020+
// wpkh tests, uncompressed and x-only keys not supported
2021+
Desc::from_str(&format!("wpkh({})", comp_key)).unwrap();
2022+
Desc::from_str(&format!("wpkh({})", uncomp_key)).unwrap_err();
2023+
Desc::from_str(&format!("wpkh({})", x_only_key)).unwrap_err();
2024+
2025+
// Segwitv0 tests, uncompressed and x-only keys not supported
2026+
Desc::from_str(&format!("wsh(pk({}))", comp_key)).unwrap();
2027+
Desc::from_str(&format!("wsh(pk({}))", uncomp_key)).unwrap_err();
2028+
Desc::from_str(&format!("wsh(pk({}))", x_only_key)).unwrap_err();
2029+
2030+
// Tap tests, key path
2031+
Desc::from_str(&format!("tr({})", comp_key)).unwrap();
2032+
Desc::from_str(&format!("tr({})", uncomp_key)).unwrap_err();
2033+
Desc::from_str(&format!("tr({})", x_only_key)).unwrap();
2034+
2035+
// Tap tests, script path
2036+
Desc::from_str(&format!("tr({},pk({}))", x_only_key, comp_key)).unwrap();
2037+
Desc::from_str(&format!("tr({},pk({}))", x_only_key, uncomp_key)).unwrap_err();
2038+
Desc::from_str(&format!("tr({},pk({}))", x_only_key, x_only_key)).unwrap();
2039+
}
20242040
}

src/descriptor/segwitv0.rs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ use crate::policy::{semantic, Liftable};
1818
use crate::prelude::*;
1919
use crate::util::varint_len;
2020
use crate::{
21-
Error, ForEachKey, Miniscript, MiniscriptKey, Satisfier, Segwitv0, ToPublicKey, TranslatePk,
22-
Translator,
21+
Error, ForEachKey, Miniscript, MiniscriptKey, Satisfier, Segwitv0, ToPublicKey, TranslateErr,
22+
TranslatePk, Translator,
2323
};
2424
/// A Segwitv0 wsh descriptor
2525
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
@@ -282,7 +282,7 @@ where
282282
{
283283
type Output = Wsh<Q>;
284284

285-
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, E>
285+
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, TranslateErr<E>>
286286
where
287287
T: Translator<P, Q, E>,
288288
{
@@ -303,14 +303,11 @@ pub struct Wpkh<Pk: MiniscriptKey> {
303303

304304
impl<Pk: MiniscriptKey> Wpkh<Pk> {
305305
/// Create a new Wpkh descriptor
306-
pub fn new(pk: Pk) -> Result<Self, Error> {
306+
pub fn new(pk: Pk) -> Result<Self, ScriptContextError> {
307307
// do the top-level checks
308-
if pk.is_uncompressed() {
309-
Err(Error::ContextError(ScriptContextError::CompressedOnly(
310-
pk.to_string(),
311-
)))
312-
} else {
313-
Ok(Self { pk })
308+
match Segwitv0::check_pk(&pk) {
309+
Ok(_) => Ok(Wpkh { pk }),
310+
Err(e) => Err(e),
314311
}
315312
}
316313

@@ -483,10 +480,14 @@ where
483480
{
484481
type Output = Wpkh<Q>;
485482

486-
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, E>
483+
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, TranslateErr<E>>
487484
where
488485
T: Translator<P, Q, E>,
489486
{
490-
Ok(Wpkh::new(t.pk(&self.pk)?).expect("Uncompressed keys in Wpkh"))
487+
let res = Wpkh::new(t.pk(&self.pk)?);
488+
match res {
489+
Ok(pk) => Ok(pk),
490+
Err(e) => Err(TranslateErr::OuterError(Error::from(e))),
491+
}
491492
}
492493
}

src/descriptor/sh.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use crate::prelude::*;
2323
use crate::util::{varint_len, witness_to_scriptsig};
2424
use crate::{
2525
push_opcode_size, Error, ForEachKey, Legacy, Miniscript, MiniscriptKey, Satisfier, Segwitv0,
26-
ToPublicKey, TranslatePk, Translator,
26+
ToPublicKey, TranslateErr, TranslatePk, Translator,
2727
};
2828

2929
/// A Legacy p2sh Descriptor
@@ -437,7 +437,7 @@ where
437437
{
438438
type Output = Sh<Q>;
439439

440-
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, E>
440+
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, TranslateErr<E>>
441441
where
442442
T: Translator<P, Q, E>,
443443
{

0 commit comments

Comments
 (0)