Skip to content

Commit afe0665

Browse files
authored
Merge pull request #209 from LLFourn/satisfaction-weight-doesnt-need-ctx
Remove ToPkCtx from length/satisfaction_weight
2 parents 9f2f263 + 6b37337 commit afe0665

File tree

7 files changed

+54
-92
lines changed

7 files changed

+54
-92
lines changed

examples/sign_multisig.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,16 +83,16 @@ fn main() {
8383
let my_descriptor =
8484
BitcoinDescriptor::from_str(&descriptor_str[..]).expect("parse descriptor string");
8585

86+
// Check weight for witness satisfaction cost ahead of time.
87+
// 4(scriptSig length of 0) + 1(witness stack size) + 106(serialized witnessScript)
88+
// + 73*2(signature length + signatures + sighash bytes) + 1(dummy byte) = 258
89+
assert_eq!(my_descriptor.max_satisfaction_weight().unwrap(), 258);
90+
8691
// Sometimes it is necessary to have additional information to get the bitcoin::PublicKey
8792
// from the MiniscriptKey which can supplied by `to_pk_ctx` parameter. For example,
8893
// when calculating the script pubkey of a descriptor with xpubs, the secp context and
8994
// child information maybe required.
9095

91-
// Check weight for witness satisfaction cost ahead of time.
92-
// 4(scriptSig length of 0) + 1(witness stack size) + 106(serialized witnessScript)
93-
// + 73*2(signature length + signatures + sighash bytes) + 1(dummy byte) = 258
94-
assert_eq!(my_descriptor.max_satisfaction_weight(NullCtx).unwrap(), 258);
95-
9696
// Observe the script properties, just for fun
9797
assert_eq!(
9898
format!("{:x}", my_descriptor.script_pubkey(NullCtx)),

fuzz/fuzz_targets/roundtrip_miniscript_script.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ fn do_test(data: &[u8]) {
1111

1212
if let Ok(pt) = Miniscript::<_, Segwitv0>::parse(&script) {
1313
let output = pt.encode(NullCtx);
14-
assert_eq!(pt.script_size(NullCtx), output.len());
14+
assert_eq!(pt.script_size(), output.len());
1515
assert_eq!(output, script);
1616
}
1717
}

src/descriptor/mod.rs

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -527,10 +527,7 @@ impl<Pk: MiniscriptKey> Descriptor<Pk> {
527527
/// transaction. Assumes all signatures are 73 bytes, including push opcode
528528
/// and sighash suffix. Includes the weight of the VarInts encoding the
529529
/// scriptSig and witness stack length.
530-
pub fn max_satisfaction_weight<ToPkCtx: Copy>(&self, to_pk_ctx: ToPkCtx) -> Option<usize>
531-
where
532-
Pk: ToPublicKey<ToPkCtx>,
533-
{
530+
pub fn max_satisfaction_weight(&self) -> Option<usize> {
534531
fn varint_len(n: usize) -> usize {
535532
bitcoin::VarInt(n as u64).len()
536533
}
@@ -541,47 +538,47 @@ impl<Pk: MiniscriptKey> Descriptor<Pk> {
541538
4 * (varint_len(scriptsig_len) + scriptsig_len)
542539
}
543540
Descriptor::Pk(..) => 4 * (1 + 73),
544-
Descriptor::Pkh(ref pk) => 4 * (1 + 73 + pk.serialized_len(to_pk_ctx)),
545-
Descriptor::Wpkh(ref pk) => 4 + 1 + 73 + pk.serialized_len(to_pk_ctx),
546-
Descriptor::ShWpkh(ref pk) => 4 * 24 + 1 + 73 + pk.serialized_len(to_pk_ctx),
541+
Descriptor::Pkh(ref pk) => 4 * (1 + 73 + pk.serialized_len()),
542+
Descriptor::Wpkh(ref pk) => 4 + 1 + 73 + pk.serialized_len(),
543+
Descriptor::ShWpkh(ref pk) => 4 * 24 + 1 + 73 + pk.serialized_len(),
547544
Descriptor::Sh(ref ms) => {
548-
let ss = ms.script_size(to_pk_ctx);
545+
let ss = ms.script_size();
549546
let ps = push_opcode_size(ss);
550547
let scriptsig_len = ps + ss + ms.max_satisfaction_size()?;
551548
4 * (varint_len(scriptsig_len) + scriptsig_len)
552549
}
553550
Descriptor::Wsh(ref ms) => {
554-
let script_size = ms.script_size(to_pk_ctx);
551+
let script_size = ms.script_size();
555552
4 + // scriptSig length byte
556553
varint_len(script_size) +
557554
script_size +
558555
varint_len(ms.max_satisfaction_witness_elements()?) +
559556
ms.max_satisfaction_size()?
560557
}
561558
Descriptor::ShWsh(ref ms) => {
562-
let script_size = ms.script_size(to_pk_ctx);
559+
let script_size = ms.script_size();
563560
4 * 36
564561
+ varint_len(script_size)
565562
+ script_size
566563
+ varint_len(ms.max_satisfaction_witness_elements()?)
567564
+ ms.max_satisfaction_size()?
568565
}
569566
Descriptor::ShSortedMulti(ref smv) => {
570-
let ss = smv.script_size(to_pk_ctx);
567+
let ss = smv.script_size();
571568
let ps = push_opcode_size(ss);
572569
let scriptsig_len = ps + ss + smv.max_satisfaction_size(1);
573570
4 * (varint_len(scriptsig_len) + scriptsig_len)
574571
}
575572
Descriptor::WshSortedMulti(ref smv) => {
576-
let script_size = smv.script_size(to_pk_ctx);
573+
let script_size = smv.script_size();
577574
4 + // scriptSig length byte
578575
varint_len(script_size) +
579576
script_size +
580577
varint_len(smv.max_satisfaction_witness_elements()) +
581578
smv.max_satisfaction_size(2)
582579
}
583580
Descriptor::ShWshSortedMulti(ref smv) => {
584-
let script_size = smv.script_size(to_pk_ctx);
581+
let script_size = smv.script_size();
585582
4 * 36
586583
+ varint_len(script_size)
587584
+ script_size
@@ -988,19 +985,11 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> SortedMultiVec<Pk, Ctx> {
988985
/// In general, it is not recommended to use this function directly, but
989986
/// to instead call the corresponding function on a `Descriptor`, which
990987
/// will handle the segwit/non-segwit technicalities for you.
991-
pub fn script_size<ToPkCtx>(&self, to_pk_ctx: ToPkCtx) -> usize
992-
where
993-
ToPkCtx: Copy,
994-
Pk: ToPublicKey<ToPkCtx>,
995-
{
988+
pub fn script_size(&self) -> usize {
996989
script_num_size(self.k)
997990
+ 1
998991
+ script_num_size(self.pks.len())
999-
+ self
1000-
.pks
1001-
.iter()
1002-
.map(|pk| ToPublicKey::serialized_len(pk, to_pk_ctx))
1003-
.sum::<usize>()
992+
+ self.pks.iter().map(|pk| pk.serialized_len()).sum::<usize>()
1004993
}
1005994

1006995
/// Maximum number of witness elements used to satisfy the Miniscript

src/lib.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
//! assert!(desc.sanity_check().is_ok());
8888
//!
8989
//! // Estimate the satisfaction cost
90-
//! assert_eq!(desc.max_satisfaction_weight(NullCtx).unwrap(), 293);
90+
//! assert_eq!(desc.max_satisfaction_weight().unwrap(), 293);
9191
//! }
9292
//! ```
9393
//!
@@ -149,6 +149,16 @@ pub trait MiniscriptKey:
149149

150150
/// Converts an object to PublicHash
151151
fn to_pubkeyhash(&self) -> Self::Hash;
152+
153+
/// Computes the size of a public key when serialized in a script,
154+
/// including the length bytes
155+
fn serialized_len(&self) -> usize {
156+
if self.is_uncompressed() {
157+
66
158+
} else {
159+
34
160+
}
161+
}
152162
}
153163

154164
impl MiniscriptKey for bitcoin::PublicKey {
@@ -191,16 +201,6 @@ pub trait ToPublicKey<ToPkCtx: Copy>: MiniscriptKey {
191201
/// extended pubkeys
192202
fn to_public_key(&self, to_pk_ctx: ToPkCtx) -> bitcoin::PublicKey;
193203

194-
/// Computes the size of a public key when serialized in a script,
195-
/// including the length bytes
196-
fn serialized_len(&self, to_pk_ctx: ToPkCtx) -> usize {
197-
if self.to_public_key(to_pk_ctx).compressed {
198-
34
199-
} else {
200-
66
201-
}
202-
}
203-
204204
/// Converts a hashed version of the public key to a `hash160` hash.
205205
///
206206
/// This method must be consistent with `to_public_key`, in the sense

src/miniscript/astelem.rs

Lines changed: 18 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -707,12 +707,9 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
707707
/// In general, it is not recommended to use this function directly, but
708708
/// to instead call the corresponding function on a `Descriptor`, which
709709
/// will handle the segwit/non-segwit technicalities for you.
710-
pub fn script_size<ToPkCtx: Copy>(&self, to_pk_ctx: ToPkCtx) -> usize
711-
where
712-
Pk: ToPublicKey<ToPkCtx>,
713-
{
710+
pub fn script_size(&self) -> usize {
714711
match *self {
715-
Terminal::PkK(ref pk) => pk.serialized_len(to_pk_ctx),
712+
Terminal::PkK(ref pk) => pk.serialized_len(),
716713
Terminal::PkH(..) => 24,
717714
Terminal::After(n) => script_num_size(n as usize) + 1,
718715
Terminal::Older(n) => script_num_size(n as usize) + 1,
@@ -722,55 +719,37 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
722719
Terminal::Hash160(..) => 21 + 6,
723720
Terminal::True => 1,
724721
Terminal::False => 1,
725-
Terminal::Alt(ref sub) => sub.node.script_size(to_pk_ctx) + 2,
726-
Terminal::Swap(ref sub) => sub.node.script_size(to_pk_ctx) + 1,
727-
Terminal::Check(ref sub) => sub.node.script_size(to_pk_ctx) + 1,
728-
Terminal::DupIf(ref sub) => sub.node.script_size(to_pk_ctx) + 3,
722+
Terminal::Alt(ref sub) => sub.node.script_size() + 2,
723+
Terminal::Swap(ref sub) => sub.node.script_size() + 1,
724+
Terminal::Check(ref sub) => sub.node.script_size() + 1,
725+
Terminal::DupIf(ref sub) => sub.node.script_size() + 3,
729726
Terminal::Verify(ref sub) => {
730-
sub.node.script_size(to_pk_ctx) + if sub.ext.has_free_verify { 0 } else { 1 }
731-
}
732-
Terminal::NonZero(ref sub) => sub.node.script_size(to_pk_ctx) + 4,
733-
Terminal::ZeroNotEqual(ref sub) => sub.node.script_size(to_pk_ctx) + 1,
734-
Terminal::AndV(ref l, ref r) => {
735-
l.node.script_size(to_pk_ctx) + r.node.script_size(to_pk_ctx)
736-
}
737-
Terminal::AndB(ref l, ref r) => {
738-
l.node.script_size(to_pk_ctx) + r.node.script_size(to_pk_ctx) + 1
727+
sub.node.script_size() + if sub.ext.has_free_verify { 0 } else { 1 }
739728
}
729+
Terminal::NonZero(ref sub) => sub.node.script_size() + 4,
730+
Terminal::ZeroNotEqual(ref sub) => sub.node.script_size() + 1,
731+
Terminal::AndV(ref l, ref r) => l.node.script_size() + r.node.script_size(),
732+
Terminal::AndB(ref l, ref r) => l.node.script_size() + r.node.script_size() + 1,
740733
Terminal::AndOr(ref a, ref b, ref c) => {
741-
a.node.script_size(to_pk_ctx)
742-
+ b.node.script_size(to_pk_ctx)
743-
+ c.node.script_size(to_pk_ctx)
744-
+ 3
745-
}
746-
Terminal::OrB(ref l, ref r) => {
747-
l.node.script_size(to_pk_ctx) + r.node.script_size(to_pk_ctx) + 1
748-
}
749-
Terminal::OrD(ref l, ref r) => {
750-
l.node.script_size(to_pk_ctx) + r.node.script_size(to_pk_ctx) + 3
751-
}
752-
Terminal::OrC(ref l, ref r) => {
753-
l.node.script_size(to_pk_ctx) + r.node.script_size(to_pk_ctx) + 2
754-
}
755-
Terminal::OrI(ref l, ref r) => {
756-
l.node.script_size(to_pk_ctx) + r.node.script_size(to_pk_ctx) + 3
734+
a.node.script_size() + b.node.script_size() + c.node.script_size() + 3
757735
}
736+
Terminal::OrB(ref l, ref r) => l.node.script_size() + r.node.script_size() + 1,
737+
Terminal::OrD(ref l, ref r) => l.node.script_size() + r.node.script_size() + 3,
738+
Terminal::OrC(ref l, ref r) => l.node.script_size() + r.node.script_size() + 2,
739+
Terminal::OrI(ref l, ref r) => l.node.script_size() + r.node.script_size() + 3,
758740
Terminal::Thresh(k, ref subs) => {
759741
assert!(!subs.is_empty(), "threshold must be nonempty");
760742
script_num_size(k) // k
761743
+ 1 // EQUAL
762-
+ subs.iter().map(|s| s.node.script_size(to_pk_ctx)).sum::<usize>()
744+
+ subs.iter().map(|s| s.node.script_size()).sum::<usize>()
763745
+ subs.len() // ADD
764746
- 1 // no ADD on first element
765747
}
766748
Terminal::Multi(k, ref pks) => {
767749
script_num_size(k)
768750
+ 1
769751
+ script_num_size(pks.len())
770-
+ pks
771-
.iter()
772-
.map(|pk| pk.serialized_len(to_pk_ctx))
773-
.sum::<usize>()
752+
+ pks.iter().map(|pk| pk.serialized_len()).sum::<usize>()
774753
}
775754
}
776755
}

src/miniscript/mod.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -197,11 +197,8 @@ where
197197
/// In general, it is not recommended to use this function directly, but
198198
/// to instead call the corresponding function on a `Descriptor`, which
199199
/// will handle the segwit/non-segwit technicalities for you.
200-
pub fn script_size<ToPkCtx: Copy>(&self, to_pk_ctx: ToPkCtx) -> usize
201-
where
202-
Pk: ToPublicKey<ToPkCtx>,
203-
{
204-
self.node.script_size(to_pk_ctx)
200+
pub fn script_size(&self) -> usize {
201+
self.node.script_size()
205202
}
206203
}
207204

@@ -471,7 +468,7 @@ mod tests {
471468
fn script_rtt<Str1: Into<Option<&'static str>>>(script: Segwitv0Script, expected_hex: Str1) {
472469
assert_eq!(script.ty.corr.base, types::Base::B);
473470
let bitcoin_script = script.encode(NullCtx);
474-
assert_eq!(bitcoin_script.len(), script.script_size(NullCtx));
471+
assert_eq!(bitcoin_script.len(), script.script_size());
475472
if let Some(expected) = expected_hex.into() {
476473
assert_eq!(format!("{:x}", bitcoin_script), expected);
477474
}
@@ -483,7 +480,7 @@ mod tests {
483480
fn roundtrip(tree: &Segwitv0Script, s: &str) {
484481
assert_eq!(tree.ty.corr.base, types::Base::B);
485482
let ser = tree.encode(NullCtx);
486-
assert_eq!(ser.len(), tree.script_size(NullCtx));
483+
assert_eq!(ser.len(), tree.script_size());
487484
assert_eq!(ser.to_string(), s);
488485
let deser = Segwitv0Script::parse_insane(&ser).expect("deserialize result of serialize");
489486
assert_eq!(*tree, deser);

src/policy/compiler.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1451,14 +1451,11 @@ mod tests {
14511451
let big_thresh_ms: SegwitMiniScript = big_thresh.compile().unwrap();
14521452
if *k == 21 {
14531453
// N * (PUSH + pubkey + CHECKSIGVERIFY)
1454-
assert_eq!(
1455-
big_thresh_ms.script_size(NullCtx),
1456-
keys.len() * (1 + 33 + 1)
1457-
);
1454+
assert_eq!(big_thresh_ms.script_size(), keys.len() * (1 + 33 + 1));
14581455
} else {
14591456
// N * (PUSH + pubkey + CHECKSIG + ADD + SWAP) + N EQUAL
14601457
assert_eq!(
1461-
big_thresh_ms.script_size(NullCtx),
1458+
big_thresh_ms.script_size(),
14621459
keys.len() * (1 + 33 + 3) + script_num_size(*k) + 1 - 2 // minus one SWAP and one ADD
14631460
);
14641461
let big_thresh_ms_expected = ms_str!(
@@ -1490,7 +1487,7 @@ mod tests {
14901487
(1, Concrete::Threshold(keys_b.len(), keys_b)),
14911488
])
14921489
.compile();
1493-
let script_size = thresh_res.clone().and_then(|m| Ok(m.script_size(NullCtx)));
1490+
let script_size = thresh_res.clone().and_then(|m| Ok(m.script_size()));
14941491
assert_eq!(
14951492
thresh_res,
14961493
Err(CompilerError::LimitsExceeded),

0 commit comments

Comments
 (0)