Skip to content

Commit f6ffc3e

Browse files
committed
Merge #657: compiler: improve logic when deciding between conjunctions and multi/multi_a
200991d compiler: improve logic for deciding between thresholds and ands (Andrew Poelstra) bc3b8dc policy: rename Threshold variant to Thresh (Andrew Poelstra) 78db616 consolidate some FIXMEs (Andrew Poelstra) 0666aef error: remove some unused variants (Andrew Poelstra) b2ec4a8 clippy: fix some nits introduced by #651 (Andrew Poelstra) Pull request description: The compiler logic when encountering thresholds of pks is currently a bit confused, and therefore chooses multi/multi_a in cases where this is not the most efficient compilation. This PR fixes that, and also brings in a few other cleanup commits that I had laying around. This does **not** fix #656, which I didn't know how to approach. ACKs for top commit: sanket1729: ACK 200991d Tree-SHA512: 252a60891cf1c1d1cd3ded88d97122fd1e76bd25807770f4843ae68bd2d854fc617518f26be86dcb57cd7fc369e1a4be81daa42ee1a6d4bc976dbad6dc1150f6
2 parents b68bf13 + 200991d commit f6ffc3e

File tree

12 files changed

+145
-202
lines changed

12 files changed

+145
-202
lines changed

examples/taproot.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ fn main() {
4545
let desc = pol.compile_tr(Some("UNSPENDABLE_KEY".to_string())).unwrap();
4646

4747
let expected_desc =
48-
Descriptor::<String>::from_str("tr(Ca,{and_v(v:pk(In),older(9)),multi_a(2,hA,S)})")
48+
Descriptor::<String>::from_str("tr(Ca,{and_v(v:pk(In),older(9)),and_v(v:pk(hA),pk(S))})")
4949
.unwrap();
5050
assert_eq!(desc, expected_desc);
5151

@@ -73,7 +73,7 @@ fn main() {
7373
);
7474
assert_eq!(
7575
iter.next().unwrap(),
76-
(1u8, &Miniscript::<String, Tap>::from_str("multi_a(2,hA,S)").unwrap())
76+
(1u8, &Miniscript::<String, Tap>::from_str("and_v(v:pk(hA),pk(S))").unwrap())
7777
);
7878
assert_eq!(iter.next(), None);
7979
}
@@ -97,19 +97,19 @@ fn main() {
9797
let real_desc = desc.translate_pk(&mut t).unwrap();
9898

9999
// Max satisfaction weight for compilation, corresponding to the script-path spend
100-
// `multi_a(2,PUBKEY_1,PUBKEY_2) at tap tree depth 1, having:
100+
// `and_v(PUBKEY_1,PUBKEY_2) at tap tree depth 1, having:
101101
//
102102
// max_witness_size = varint(control_block_size) + control_block size +
103103
// varint(script_size) + script_size + max_satisfaction_size
104-
// = 1 + 65 + 1 + 70 + 132 = 269
104+
// = 1 + 65 + 1 + 68 + 132 = 269
105105
let max_sat_wt = real_desc.max_weight_to_satisfy().unwrap();
106-
assert_eq!(max_sat_wt, 269);
106+
assert_eq!(max_sat_wt, 267);
107107

108108
// Compute the bitcoin address and check if it matches
109109
let network = Network::Bitcoin;
110110
let addr = real_desc.address(network).unwrap();
111111
let expected_addr = bitcoin::Address::from_str(
112-
"bc1pcc8ku64slu3wu04a6g376d2s8ck9y5alw5sus4zddvn8xgpdqw2swrghwx",
112+
"bc1p4l2xzq7js40965s5w0fknd287kdlmt2dljte37zsc5a34u0h9c4q85snyd",
113113
)
114114
.unwrap()
115115
.assume_checked();

src/descriptor/sortedmulti.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> SortedMultiVec<Pk, Ctx> {
198198

199199
impl<Pk: MiniscriptKey, Ctx: ScriptContext> policy::Liftable<Pk> for SortedMultiVec<Pk, Ctx> {
200200
fn lift(&self) -> Result<policy::semantic::Policy<Pk>, Error> {
201-
let ret = policy::semantic::Policy::Threshold(
201+
let ret = policy::semantic::Policy::Thresh(
202202
self.k,
203203
self.pks
204204
.iter()

src/descriptor/tr.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@ impl<Pk: MiniscriptKey> Liftable<Pk> for TapTree<Pk> {
616616
fn lift(&self) -> Result<Policy<Pk>, Error> {
617617
fn lift_helper<Pk: MiniscriptKey>(s: &TapTree<Pk>) -> Result<Policy<Pk>, Error> {
618618
match *s {
619-
TapTree::Tree { ref left, ref right, height: _ } => Ok(Policy::Threshold(
619+
TapTree::Tree { ref left, ref right, height: _ } => Ok(Policy::Thresh(
620620
1,
621621
vec![Arc::new(lift_helper(left)?), Arc::new(lift_helper(right)?)],
622622
)),
@@ -632,7 +632,7 @@ impl<Pk: MiniscriptKey> Liftable<Pk> for TapTree<Pk> {
632632
impl<Pk: MiniscriptKey> Liftable<Pk> for Tr<Pk> {
633633
fn lift(&self) -> Result<Policy<Pk>, Error> {
634634
match &self.tree {
635-
Some(root) => Ok(Policy::Threshold(
635+
Some(root) => Ok(Policy::Thresh(
636636
1,
637637
vec![
638638
Arc::new(Policy::Key(self.internal_key.clone())),

src/lib.rs

-44
Original file line numberDiff line numberDiff line change
@@ -443,8 +443,6 @@ pub enum Error {
443443
Unexpected(String),
444444
/// Name of a fragment contained `:` multiple times
445445
MultiColon(String),
446-
/// Name of a fragment contained `@` multiple times
447-
MultiAt(String),
448446
/// Name of a fragment contained `@` but we were not parsing an OR
449447
AtOutsideOr(String),
450448
/// Encountered a wrapping character that we don't recognize
@@ -453,16 +451,8 @@ pub enum Error {
453451
NonTopLevel(String),
454452
/// Parsed a miniscript but there were more script opcodes after it
455453
Trailing(String),
456-
/// Failed to parse a push as a public key
457-
BadPubkey(bitcoin::key::Error),
458-
/// Could not satisfy a script (fragment) because of a missing hash preimage
459-
MissingHash(sha256::Hash),
460454
/// Could not satisfy a script (fragment) because of a missing signature
461455
MissingSig(bitcoin::PublicKey),
462-
/// Could not satisfy, relative locktime not met
463-
RelativeLocktimeNotMet(u32),
464-
/// Could not satisfy, absolute locktime not met
465-
AbsoluteLocktimeNotMet(u32),
466456
/// General failure to satisfy
467457
CouldNotSatisfy,
468458
/// Typechecking failed
@@ -482,8 +472,6 @@ pub enum Error {
482472
ContextError(miniscript::context::ScriptContextError),
483473
/// Recursion depth exceeded when parsing policy/miniscript from string
484474
MaxRecursiveDepthExceeded,
485-
/// Script size too large
486-
ScriptSizeTooLarge,
487475
/// Anything but c:pk(key) (P2PK), c:pk_h(key) (P2PKH), and thresh_m(k,...)
488476
/// up to n=3 is invalid by standardness (bare)
489477
NonStandardBareScript,
@@ -495,12 +483,8 @@ pub enum Error {
495483
BareDescriptorAddr,
496484
/// PubKey invalid under current context
497485
PubKeyCtxError(miniscript::decode::KeyParseError, &'static str),
498-
/// Attempted to call function that requires PreComputed taproot info
499-
TaprootSpendInfoUnavialable,
500486
/// No script code for Tr descriptors
501487
TrNoScriptCode,
502-
/// No explicit script for Tr descriptors
503-
TrNoExplicitScript,
504488
/// At least two BIP389 key expressions in the descriptor contain tuples of
505489
/// derivation indexes of different lengths.
506490
MultipathDescLenMismatch,
@@ -512,8 +496,6 @@ pub enum Error {
512496

513497
// https://github.com/sipa/miniscript/pull/5 for discussion on this number
514498
const MAX_RECURSION_DEPTH: u32 = 402;
515-
// https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki
516-
const MAX_SCRIPT_SIZE: u32 = 10000;
517499

518500
impl fmt::Display for Error {
519501
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -531,23 +513,12 @@ impl fmt::Display for Error {
531513
Error::UnexpectedStart => f.write_str("unexpected start of script"),
532514
Error::Unexpected(ref s) => write!(f, "unexpected «{}»", s),
533515
Error::MultiColon(ref s) => write!(f, "«{}» has multiple instances of «:»", s),
534-
Error::MultiAt(ref s) => write!(f, "«{}» has multiple instances of «@»", s),
535516
Error::AtOutsideOr(ref s) => write!(f, "«{}» contains «@» in non-or() context", s),
536517
Error::UnknownWrapper(ch) => write!(f, "unknown wrapper «{}:»", ch),
537518
Error::NonTopLevel(ref s) => write!(f, "non-T miniscript: {}", s),
538519
Error::Trailing(ref s) => write!(f, "trailing tokens: {}", s),
539-
Error::MissingHash(ref h) => write!(f, "missing preimage of hash {}", h),
540520
Error::MissingSig(ref pk) => write!(f, "missing signature for key {:?}", pk),
541-
Error::RelativeLocktimeNotMet(n) => {
542-
write!(f, "required relative locktime CSV of {} blocks, not met", n)
543-
}
544-
Error::AbsoluteLocktimeNotMet(n) => write!(
545-
f,
546-
"required absolute locktime CLTV of {} blocks, not met",
547-
n
548-
),
549521
Error::CouldNotSatisfy => f.write_str("could not satisfy"),
550-
Error::BadPubkey(ref e) => fmt::Display::fmt(e, f),
551522
Error::TypeCheck(ref e) => write!(f, "typecheck: {}", e),
552523
Error::BadDescriptor(ref e) => write!(f, "Invalid descriptor: {}", e),
553524
Error::Secp(ref e) => fmt::Display::fmt(e, f),
@@ -561,11 +532,6 @@ impl fmt::Display for Error {
561532
"Recursive depth over {} not permitted",
562533
MAX_RECURSION_DEPTH
563534
),
564-
Error::ScriptSizeTooLarge => write!(
565-
f,
566-
"Standardness rules imply bitcoin than {} bytes",
567-
MAX_SCRIPT_SIZE
568-
),
569535
Error::NonStandardBareScript => write!(
570536
f,
571537
"Anything but c:pk(key) (P2PK), c:pk_h(key) (P2PKH), and thresh_m(k,...) \
@@ -579,9 +545,7 @@ impl fmt::Display for Error {
579545
write!(f, "Pubkey error: {} under {} scriptcontext", pk, ctx)
580546
}
581547
Error::MultiATooManyKeys(k) => write!(f, "MultiA too many keys {}", k),
582-
Error::TaprootSpendInfoUnavialable => write!(f, "Taproot Spend Info not computed."),
583548
Error::TrNoScriptCode => write!(f, "No script code for Tr descriptors"),
584-
Error::TrNoExplicitScript => write!(f, "No script code for Tr descriptors"),
585549
Error::MultipathDescLenMismatch => write!(f, "At least two BIP389 key expressions in the descriptor contain tuples of derivation indexes of different lengths"),
586550
Error::AbsoluteLockTime(ref e) => e.fmt(f),
587551
Error::RelativeLockTime(ref e) => e.fmt(f),
@@ -605,30 +569,22 @@ impl error::Error for Error {
605569
| UnexpectedStart
606570
| Unexpected(_)
607571
| MultiColon(_)
608-
| MultiAt(_)
609572
| AtOutsideOr(_)
610573
| UnknownWrapper(_)
611574
| NonTopLevel(_)
612575
| Trailing(_)
613-
| MissingHash(_)
614576
| MissingSig(_)
615-
| RelativeLocktimeNotMet(_)
616-
| AbsoluteLocktimeNotMet(_)
617577
| CouldNotSatisfy
618578
| TypeCheck(_)
619579
| BadDescriptor(_)
620580
| MaxRecursiveDepthExceeded
621-
| ScriptSizeTooLarge
622581
| NonStandardBareScript
623582
| ImpossibleSatisfaction
624583
| BareDescriptorAddr
625-
| TaprootSpendInfoUnavialable
626584
| TrNoScriptCode
627-
| TrNoExplicitScript
628585
| MultipathDescLenMismatch => None,
629586
Script(e) => Some(e),
630587
AddrError(e) => Some(e),
631-
BadPubkey(e) => Some(e),
632588
Secp(e) => Some(e),
633589
#[cfg(feature = "compiler")]
634590
CompilerError(e) => Some(e),

src/miniscript/astelem.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ fn fmt_1<D: fmt::Debug + fmt::Display>(
139139
a: &D,
140140
is_debug: bool,
141141
) -> fmt::Result {
142-
f.write_str(&name)?;
142+
f.write_str(name)?;
143143
conditional_fmt(f, a, is_debug)?;
144144
f.write_str(")")
145145
}
@@ -150,7 +150,7 @@ fn fmt_2<D: fmt::Debug + fmt::Display>(
150150
b: &D,
151151
is_debug: bool,
152152
) -> fmt::Result {
153-
f.write_str(&name)?;
153+
f.write_str(name)?;
154154
conditional_fmt(f, a, is_debug)?;
155155
f.write_str(",")?;
156156
conditional_fmt(f, b, is_debug)?;
@@ -163,7 +163,7 @@ fn fmt_n<D: fmt::Debug + fmt::Display>(
163163
list: &[D],
164164
is_debug: bool,
165165
) -> fmt::Result {
166-
f.write_str(&name)?;
166+
f.write_str(name)?;
167167
write!(f, "{}", first)?;
168168
for el in list {
169169
f.write_str(",")?;

src/miniscript/decode.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@ use core::marker::PhantomData;
1111
use std::error;
1212

1313
use bitcoin::hashes::{hash160, ripemd160, sha256, Hash};
14-
use bitcoin::Weight;
1514
use sync::Arc;
1615

1716
use crate::miniscript::lex::{Token as Tk, TokenIter};
18-
use crate::miniscript::limits::MAX_PUBKEYS_PER_MULTISIG;
17+
use crate::miniscript::limits::{MAX_PUBKEYS_IN_CHECKSIGADD, MAX_PUBKEYS_PER_MULTISIG};
1918
use crate::miniscript::types::extra_props::ExtData;
2019
use crate::miniscript::types::Type;
2120
use crate::miniscript::ScriptContext;
@@ -451,10 +450,9 @@ pub fn parse<Ctx: ScriptContext>(
451450
},
452451
// MultiA
453452
Tk::NumEqual, Tk::Num(k) => {
454-
let max = Weight::MAX_BLOCK.to_wu() / 32;
455453
// Check size before allocating keys
456-
if k as u64 > max {
457-
return Err(Error::MultiATooManyKeys(max))
454+
if k as usize > MAX_PUBKEYS_IN_CHECKSIGADD {
455+
return Err(Error::MultiATooManyKeys(MAX_PUBKEYS_IN_CHECKSIGADD as u64))
458456
}
459457
let mut keys = Vec::with_capacity(k as usize); // atleast k capacity
460458
while tokens.peek() == Some(&Tk::CheckSigAdd) {

src/miniscript/limits.rs

+2
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,5 @@ pub const MAX_BLOCK_WEIGHT: usize = 4000000;
3333
/// Maximum pubkeys as arguments to CHECKMULTISIG
3434
// https://github.com/bitcoin/bitcoin/blob/6acda4b00b3fc1bfac02f5de590e1a5386cbc779/src/script/script.h#L30
3535
pub const MAX_PUBKEYS_PER_MULTISIG: usize = 20;
36+
/// Maximum pubkeys in a CHECKSIGADD construction.
37+
pub const MAX_PUBKEYS_IN_CHECKSIGADD: usize = (bitcoin::Weight::MAX_BLOCK.to_wu() / 32) as usize;

src/miniscript/types/mod.rs

+1-15
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ impl Type {
220220

221221
/// Constructor for the type of the `a:` fragment.
222222
pub const fn cast_alt(self) -> Result<Self, ErrorKind> {
223-
// FIXME need to do manual `?` because ? is not supported in constfns.
223+
// FIXME need to do manual `?` because ? is not supported in constfns. (Also below.)
224224
Ok(Type {
225225
corr: match Correctness::cast_alt(self.corr) {
226226
Ok(x) => x,
@@ -232,7 +232,6 @@ impl Type {
232232

233233
/// Constructor for the type of the `s:` fragment.
234234
pub const fn cast_swap(self) -> Result<Self, ErrorKind> {
235-
// FIXME need to do manual `?` because ? is not supported in constfns.
236235
Ok(Type {
237236
corr: match Correctness::cast_swap(self.corr) {
238237
Ok(x) => x,
@@ -255,7 +254,6 @@ impl Type {
255254

256255
/// Constructor for the type of the `d:` fragment.
257256
pub const fn cast_dupif(self) -> Result<Self, ErrorKind> {
258-
// FIXME need to do manual `?` because ? is not supported in constfns.
259257
Ok(Type {
260258
corr: match Correctness::cast_dupif(self.corr) {
261259
Ok(x) => x,
@@ -267,7 +265,6 @@ impl Type {
267265

268266
/// Constructor for the type of the `v:` fragment.
269267
pub const fn cast_verify(self) -> Result<Self, ErrorKind> {
270-
// FIXME need to do manual `?` because ? is not supported in constfns.
271268
Ok(Type {
272269
corr: match Correctness::cast_verify(self.corr) {
273270
Ok(x) => x,
@@ -279,7 +276,6 @@ impl Type {
279276

280277
/// Constructor for the type of the `j:` fragment.
281278
pub const fn cast_nonzero(self) -> Result<Self, ErrorKind> {
282-
// FIXME need to do manual `?` because ? is not supported in constfns.
283279
Ok(Type {
284280
corr: match Correctness::cast_nonzero(self.corr) {
285281
Ok(x) => x,
@@ -291,7 +287,6 @@ impl Type {
291287

292288
/// Constructor for the type of the `n:` fragment.
293289
pub const fn cast_zeronotequal(self) -> Result<Self, ErrorKind> {
294-
// FIXME need to do manual `?` because ? is not supported in constfns.
295290
Ok(Type {
296291
corr: match Correctness::cast_zeronotequal(self.corr) {
297292
Ok(x) => x,
@@ -303,7 +298,6 @@ impl Type {
303298

304299
/// Constructor for the type of the `t:` fragment.
305300
pub const fn cast_true(self) -> Result<Self, ErrorKind> {
306-
// FIXME need to do manual `?` because ? is not supported in constfns.
307301
Ok(Type {
308302
corr: match Correctness::cast_true(self.corr) {
309303
Ok(x) => x,
@@ -315,7 +309,6 @@ impl Type {
315309

316310
/// Constructor for the type of the `u:` fragment.
317311
pub const fn cast_unlikely(self) -> Result<Self, ErrorKind> {
318-
// FIXME need to do manual `?` because ? is not supported in constfns.
319312
Ok(Type {
320313
corr: match Correctness::cast_or_i_false(self.corr) {
321314
Ok(x) => x,
@@ -327,7 +320,6 @@ impl Type {
327320

328321
/// Constructor for the type of the `l:` fragment.
329322
pub const fn cast_likely(self) -> Result<Self, ErrorKind> {
330-
// FIXME need to do manual `?` because ? is not supported in constfns.
331323
Ok(Type {
332324
corr: match Correctness::cast_or_i_false(self.corr) {
333325
Ok(x) => x,
@@ -339,7 +331,6 @@ impl Type {
339331

340332
/// Constructor for the type of the `and_b` fragment.
341333
pub const fn and_b(left: Self, right: Self) -> Result<Self, ErrorKind> {
342-
// FIXME need to do manual `?` because ? is not supported in constfns.
343334
Ok(Type {
344335
corr: match Correctness::and_b(left.corr, right.corr) {
345336
Ok(x) => x,
@@ -351,7 +342,6 @@ impl Type {
351342

352343
/// Constructor for the type of the `and_v` fragment.
353344
pub const fn and_v(left: Self, right: Self) -> Result<Self, ErrorKind> {
354-
// FIXME need to do manual `?` because ? is not supported in constfns.
355345
Ok(Type {
356346
corr: match Correctness::and_v(left.corr, right.corr) {
357347
Ok(x) => x,
@@ -363,7 +353,6 @@ impl Type {
363353

364354
/// Constructor for the type of the `or_b` fragment.
365355
pub const fn or_b(left: Self, right: Self) -> Result<Self, ErrorKind> {
366-
// FIXME need to do manual `?` because ? is not supported in constfns.
367356
Ok(Type {
368357
corr: match Correctness::or_b(left.corr, right.corr) {
369358
Ok(x) => x,
@@ -375,7 +364,6 @@ impl Type {
375364

376365
/// Constructor for the type of the `or_b` fragment.
377366
pub const fn or_d(left: Self, right: Self) -> Result<Self, ErrorKind> {
378-
// FIXME need to do manual `?` because ? is not supported in constfns.
379367
Ok(Type {
380368
corr: match Correctness::or_d(left.corr, right.corr) {
381369
Ok(x) => x,
@@ -387,7 +375,6 @@ impl Type {
387375

388376
/// Constructor for the type of the `or_c` fragment.
389377
pub const fn or_c(left: Self, right: Self) -> Result<Self, ErrorKind> {
390-
// FIXME need to do manual `?` because ? is not supported in constfns.
391378
Ok(Type {
392379
corr: match Correctness::or_c(left.corr, right.corr) {
393380
Ok(x) => x,
@@ -410,7 +397,6 @@ impl Type {
410397

411398
/// Constructor for the type of the `and_or` fragment.
412399
pub const fn and_or(a: Self, b: Self, c: Self) -> Result<Self, ErrorKind> {
413-
// FIXME need to do manual `?` because ? is not supported in constfns.
414400
Ok(Type {
415401
corr: match Correctness::and_or(a.corr, b.corr, c.corr) {
416402
Ok(x) => x,

0 commit comments

Comments
 (0)