Skip to content

Commit aa36494

Browse files
committed
Update interpreter API to Witness struct
1 parent f3c38b8 commit aa36494

File tree

4 files changed

+71
-51
lines changed

4 files changed

+71
-51
lines changed

examples/verify_tx.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,10 @@ fn main() {
8383
0xa9, 0x14, 0x92, 0x09, 0xa8, 0xf9, 0x0c, 0x58, 0x4b, 0xb5, 0x97, 0x4d, 0x58, 0x68, 0x72,
8484
0x49, 0xe5, 0x32, 0xde, 0x59, 0xf4, 0xbc, 0x87,
8585
]);
86-
let wit = transaction.input[0].witness.to_vec();
8786
let mut interpreter = miniscript::Interpreter::from_txdata(
8887
&spk_input_1,
8988
&transaction.input[0].script_sig,
90-
&wit,
89+
&transaction.input[0].witness,
9190
0,
9291
0,
9392
)
@@ -123,11 +122,10 @@ fn main() {
123122
// from the MiniscriptKey which can supplied by `to_pk_ctx` parameter. For example,
124123
// when calculating the script pubkey of a descriptor with xpubs, the secp context and
125124
// child information maybe required.
126-
let wit = transaction.input[0].witness.to_vec();
127125
let mut interpreter = miniscript::Interpreter::from_txdata(
128126
&spk_input_1,
129127
&transaction.input[0].script_sig,
130-
&wit,
128+
&transaction.input[0].witness,
131129
0,
132130
0,
133131
)
@@ -158,11 +156,10 @@ fn main() {
158156
// what happens given an apparently invalid script
159157
let secp = secp256k1::Secp256k1::new();
160158
let message = secp256k1::Message::from_slice(&[0x01; 32][..]).expect("32-byte hash");
161-
let wit = transaction.input[0].witness.to_vec();
162159
let mut interpreter = miniscript::Interpreter::from_txdata(
163160
&spk_input_1,
164161
&transaction.input[0].script_sig,
165-
&wit,
162+
&transaction.input[0].witness,
166163
0,
167164
0,
168165
)

src/interpreter/inner.rs

Lines changed: 62 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
//
1414

1515
use bitcoin;
16+
use bitcoin::blockdata::witness::Witness;
1617
use bitcoin::hashes::{hash160, sha256, Hash};
1718

1819
use super::{stack, Error, Stack};
@@ -97,7 +98,7 @@ pub enum Inner {
9798
pub fn from_txdata<'txin>(
9899
spk: &bitcoin::Script,
99100
script_sig: &'txin bitcoin::Script,
100-
witness: &'txin [Vec<u8>],
101+
witness: &'txin Witness,
101102
) -> Result<(Inner, Stack<'txin>, bitcoin::Script), Error> {
102103
let mut ssig_stack: Stack = script_sig
103104
.instructions_minimal()
@@ -300,12 +301,12 @@ mod tests {
300301
pkh_sig: bitcoin::Script,
301302
pkh_sig_justkey: bitcoin::Script,
302303
wpkh_spk: bitcoin::Script,
303-
wpkh_stack: Vec<Vec<u8>>,
304-
wpkh_stack_justkey: Vec<Vec<u8>>,
304+
wpkh_stack: Witness,
305+
wpkh_stack_justkey: Witness,
305306
sh_wpkh_spk: bitcoin::Script,
306307
sh_wpkh_sig: bitcoin::Script,
307-
sh_wpkh_stack: Vec<Vec<u8>>,
308-
sh_wpkh_stack_justkey: Vec<Vec<u8>>,
308+
sh_wpkh_stack: Witness,
309+
sh_wpkh_stack_justkey: Witness,
309310
}
310311

311312
impl KeyTestData {
@@ -334,14 +335,14 @@ mod tests {
334335
.into_script(),
335336
pkh_sig_justkey: script::Builder::new().push_key(&key).into_script(),
336337
wpkh_spk: wpkh_spk.clone(),
337-
wpkh_stack: vec![dummy_sig.clone(), key.to_bytes()],
338-
wpkh_stack_justkey: vec![key.to_bytes()],
338+
wpkh_stack: Witness::from_vec(vec![dummy_sig.clone(), key.to_bytes()]),
339+
wpkh_stack_justkey: Witness::from_vec(vec![key.to_bytes()]),
339340
sh_wpkh_spk: bitcoin::Script::new_p2sh(&wpkh_scripthash),
340341
sh_wpkh_sig: script::Builder::new()
341342
.push_slice(&wpkh_spk[..])
342343
.into_script(),
343-
sh_wpkh_stack: vec![dummy_sig, key.to_bytes()],
344-
sh_wpkh_stack_justkey: vec![key.to_bytes()],
344+
sh_wpkh_stack: Witness::from_vec(vec![dummy_sig, key.to_bytes()]),
345+
sh_wpkh_stack_justkey: Witness::from_vec(vec![key.to_bytes()]),
345346
}
346347
}
347348
}
@@ -375,31 +376,32 @@ mod tests {
375376
let comp = KeyTestData::from_key(fixed.pk_comp);
376377
let uncomp = KeyTestData::from_key(fixed.pk_uncomp);
377378
let blank_script = bitcoin::Script::new();
379+
let empty_wit = Witness::default();
378380

379381
// Compressed pk, empty scriptsig
380382
let (inner, stack, script_code) =
381-
from_txdata(&comp.pk_spk, &blank_script, &[]).expect("parse txdata");
383+
from_txdata(&comp.pk_spk, &blank_script, &empty_wit).expect("parse txdata");
382384
assert_eq!(inner, Inner::PublicKey(fixed.pk_comp, PubkeyType::Pk));
383385
assert_eq!(stack, Stack::from(vec![]));
384386
assert_eq!(script_code, comp.pk_spk);
385387

386388
// Uncompressed pk, empty scriptsig
387389
let (inner, stack, script_code) =
388-
from_txdata(&uncomp.pk_spk, &blank_script, &[]).expect("parse txdata");
390+
from_txdata(&uncomp.pk_spk, &blank_script, &empty_wit).expect("parse txdata");
389391
assert_eq!(inner, Inner::PublicKey(fixed.pk_uncomp, PubkeyType::Pk));
390392
assert_eq!(stack, Stack::from(vec![]));
391393
assert_eq!(script_code, uncomp.pk_spk);
392394

393395
// Compressed pk, correct scriptsig
394396
let (inner, stack, script_code) =
395-
from_txdata(&comp.pk_spk, &comp.pk_sig, &[]).expect("parse txdata");
397+
from_txdata(&comp.pk_spk, &comp.pk_sig, &empty_wit).expect("parse txdata");
396398
assert_eq!(inner, Inner::PublicKey(fixed.pk_comp, PubkeyType::Pk));
397399
assert_eq!(stack, Stack::from(vec![comp.pk_sig[1..].into()]));
398400
assert_eq!(script_code, comp.pk_spk);
399401

400402
// Uncompressed pk, correct scriptsig
401403
let (inner, stack, script_code) =
402-
from_txdata(&uncomp.pk_spk, &uncomp.pk_sig, &[]).expect("parse txdata");
404+
from_txdata(&uncomp.pk_spk, &uncomp.pk_sig, &empty_wit).expect("parse txdata");
403405
assert_eq!(inner, Inner::PublicKey(fixed.pk_uncomp, PubkeyType::Pk));
404406
assert_eq!(stack, Stack::from(vec![uncomp.pk_sig[1..].into()]));
405407
assert_eq!(script_code, uncomp.pk_spk);
@@ -408,18 +410,19 @@ mod tests {
408410
let mut spk = comp.pk_spk.to_bytes();
409411
spk[1] = 5;
410412
let spk = bitcoin::Script::from(spk);
411-
let err = from_txdata(&spk, &bitcoin::Script::new(), &[]).unwrap_err();
413+
let err = from_txdata(&spk, &bitcoin::Script::new(), &empty_wit).unwrap_err();
412414
assert_eq!(err.to_string(), "could not parse pubkey");
413415

414416
// Scriptpubkey has invalid script
415417
let mut spk = comp.pk_spk.to_bytes();
416418
spk[0] = 100;
417419
let spk = bitcoin::Script::from(spk);
418-
let err = from_txdata(&spk, &bitcoin::Script::new(), &[]).unwrap_err();
420+
let err = from_txdata(&spk, &bitcoin::Script::new(), &empty_wit).unwrap_err();
419421
assert_eq!(&err.to_string()[0..12], "parse error:");
420422

421423
// Witness is nonempty
422-
let err = from_txdata(&comp.pk_spk, &comp.pk_sig, &[vec![]]).unwrap_err();
424+
let wit = Witness::from_vec(vec![vec![]]);
425+
let err = from_txdata(&comp.pk_spk, &comp.pk_sig, &wit).unwrap_err();
423426
assert_eq!(err.to_string(), "legacy spend had nonempty witness");
424427
}
425428

@@ -428,43 +431,47 @@ mod tests {
428431
let fixed = fixed_test_data();
429432
let comp = KeyTestData::from_key(fixed.pk_comp);
430433
let uncomp = KeyTestData::from_key(fixed.pk_uncomp);
434+
let empty_wit = Witness::default();
431435

432436
// pkh, empty scriptsig; this time it errors out
433-
let err = from_txdata(&comp.pkh_spk, &bitcoin::Script::new(), &[]).unwrap_err();
437+
let err = from_txdata(&comp.pkh_spk, &bitcoin::Script::new(), &empty_wit).unwrap_err();
434438
assert_eq!(err.to_string(), "unexpected end of stack");
435439

436440
// pkh, wrong pubkey
437-
let err = from_txdata(&comp.pkh_spk, &uncomp.pkh_sig_justkey, &[]).unwrap_err();
441+
let err = from_txdata(&comp.pkh_spk, &uncomp.pkh_sig_justkey, &empty_wit).unwrap_err();
438442
assert_eq!(err.to_string(), "public key did not match scriptpubkey");
439443

440444
// pkh, right pubkey, no signature
441445
let (inner, stack, script_code) =
442-
from_txdata(&comp.pkh_spk, &comp.pkh_sig_justkey, &[]).expect("parse txdata");
446+
from_txdata(&comp.pkh_spk, &comp.pkh_sig_justkey, &empty_wit).expect("parse txdata");
443447
assert_eq!(inner, Inner::PublicKey(fixed.pk_comp, PubkeyType::Pkh));
444448
assert_eq!(stack, Stack::from(vec![]));
445449
assert_eq!(script_code, comp.pkh_spk);
446450

447451
let (inner, stack, script_code) =
448-
from_txdata(&uncomp.pkh_spk, &uncomp.pkh_sig_justkey, &[]).expect("parse txdata");
452+
from_txdata(&uncomp.pkh_spk, &uncomp.pkh_sig_justkey, &empty_wit)
453+
.expect("parse txdata");
449454
assert_eq!(inner, Inner::PublicKey(fixed.pk_uncomp, PubkeyType::Pkh));
450455
assert_eq!(stack, Stack::from(vec![]));
451456
assert_eq!(script_code, uncomp.pkh_spk);
452457

453458
// pkh, right pubkey, signature
454459
let (inner, stack, script_code) =
455-
from_txdata(&comp.pkh_spk, &comp.pkh_sig_justkey, &[]).expect("parse txdata");
460+
from_txdata(&comp.pkh_spk, &comp.pkh_sig_justkey, &empty_wit).expect("parse txdata");
456461
assert_eq!(inner, Inner::PublicKey(fixed.pk_comp, PubkeyType::Pkh));
457462
assert_eq!(stack, Stack::from(vec![]));
458463
assert_eq!(script_code, comp.pkh_spk);
459464

460465
let (inner, stack, script_code) =
461-
from_txdata(&uncomp.pkh_spk, &uncomp.pkh_sig_justkey, &[]).expect("parse txdata");
466+
from_txdata(&uncomp.pkh_spk, &uncomp.pkh_sig_justkey, &empty_wit)
467+
.expect("parse txdata");
462468
assert_eq!(inner, Inner::PublicKey(fixed.pk_uncomp, PubkeyType::Pkh));
463469
assert_eq!(stack, Stack::from(vec![]));
464470
assert_eq!(script_code, uncomp.pkh_spk);
465471

466472
// Witness is nonempty
467-
let err = from_txdata(&comp.pkh_spk, &comp.pkh_sig, &[vec![]]).unwrap_err();
473+
let wit = Witness::from_vec(vec![vec![]]);
474+
let err = from_txdata(&comp.pkh_spk, &comp.pkh_sig, &wit).unwrap_err();
468475
assert_eq!(err.to_string(), "legacy spend had nonempty witness");
469476
}
470477

@@ -476,7 +483,7 @@ mod tests {
476483
let blank_script = bitcoin::Script::new();
477484

478485
// wpkh, empty witness; this time it errors out
479-
let err = from_txdata(&comp.wpkh_spk, &blank_script, &[]).unwrap_err();
486+
let err = from_txdata(&comp.wpkh_spk, &blank_script, &Witness::default()).unwrap_err();
480487
assert_eq!(err.to_string(), "unexpected end of stack");
481488

482489
// wpkh, uncompressed pubkey
@@ -507,7 +514,10 @@ mod tests {
507514
let (inner, stack, script_code) =
508515
from_txdata(&comp.wpkh_spk, &blank_script, &comp.wpkh_stack).expect("parse txdata");
509516
assert_eq!(inner, Inner::PublicKey(fixed.pk_comp, PubkeyType::Wpkh));
510-
assert_eq!(stack, Stack::from(vec![comp.wpkh_stack[0][..].into()]));
517+
assert_eq!(
518+
stack,
519+
Stack::from(vec![comp.wpkh_stack.second_to_last().unwrap().into()])
520+
);
511521
assert_eq!(script_code, comp.pkh_spk);
512522

513523
// Scriptsig is nonempty
@@ -523,9 +533,10 @@ mod tests {
523533
let blank_script = bitcoin::Script::new();
524534

525535
// sh_wpkh, missing witness or scriptsig
526-
let err = from_txdata(&comp.sh_wpkh_spk, &blank_script, &[]).unwrap_err();
536+
let err = from_txdata(&comp.sh_wpkh_spk, &blank_script, &Witness::default()).unwrap_err();
527537
assert_eq!(err.to_string(), "unexpected end of stack");
528-
let err = from_txdata(&comp.sh_wpkh_spk, &comp.sh_wpkh_sig, &[]).unwrap_err();
538+
let err =
539+
from_txdata(&comp.sh_wpkh_spk, &comp.sh_wpkh_sig, &Witness::default()).unwrap_err();
529540
assert_eq!(err.to_string(), "unexpected end of stack");
530541
let err = from_txdata(&comp.sh_wpkh_spk, &blank_script, &comp.sh_wpkh_stack).unwrap_err();
531542
assert_eq!(err.to_string(), "unexpected end of stack");
@@ -576,7 +587,10 @@ mod tests {
576587
from_txdata(&comp.sh_wpkh_spk, &comp.sh_wpkh_sig, &comp.sh_wpkh_stack)
577588
.expect("parse txdata");
578589
assert_eq!(inner, Inner::PublicKey(fixed.pk_comp, PubkeyType::ShWpkh));
579-
assert_eq!(stack, Stack::from(vec![comp.sh_wpkh_stack[0][..].into()]));
590+
assert_eq!(
591+
stack,
592+
Stack::from(vec![comp.sh_wpkh_stack.second_to_last().unwrap().into()])
593+
);
580594
assert_eq!(script_code, comp.pkh_spk);
581595
}
582596

@@ -589,19 +603,21 @@ mod tests {
589603

590604
let spk = miniscript.encode();
591605
let blank_script = bitcoin::Script::new();
606+
let empty_wit = Witness::default();
592607

593608
// bare script has no validity requirements beyond being a sane script
594609
let (inner, stack, script_code) =
595-
from_txdata(&spk, &blank_script, &[]).expect("parse txdata");
610+
from_txdata(&spk, &blank_script, &empty_wit).expect("parse txdata");
596611
assert_eq!(inner, Inner::Script(miniscript, ScriptType::Bare));
597612
assert_eq!(stack, Stack::from(vec![]));
598613
assert_eq!(script_code, spk);
599614

600-
let err = from_txdata(&blank_script, &blank_script, &[]).unwrap_err();
615+
let err = from_txdata(&blank_script, &blank_script, &empty_wit).unwrap_err();
601616
assert_eq!(&err.to_string()[0..12], "parse error:");
602617

603618
// nonempty witness
604-
let err = from_txdata(&spk, &blank_script, &[vec![]]).unwrap_err();
619+
let wit = Witness::from_vec(vec![vec![]]);
620+
let err = from_txdata(&spk, &blank_script, &wit).unwrap_err();
605621
assert_eq!(&err.to_string(), "legacy spend had nonempty witness");
606622
}
607623

@@ -620,24 +636,26 @@ mod tests {
620636
.push_slice(&redeem_script[..])
621637
.into_script();
622638
let blank_script = bitcoin::Script::new();
639+
let empty_wit = Witness::default();
623640

624641
// sh without scriptsig
625-
let err = from_txdata(&spk, &blank_script, &[]).unwrap_err();
642+
let err = from_txdata(&spk, &blank_script, &Witness::default()).unwrap_err();
626643
assert_eq!(&err.to_string(), "unexpected end of stack");
627644

628645
// with incorrect scriptsig
629-
let err = from_txdata(&spk, &spk, &[]).unwrap_err();
646+
let err = from_txdata(&spk, &spk, &Witness::default()).unwrap_err();
630647
assert_eq!(&err.to_string(), "expected push in script");
631648

632649
// with correct scriptsig
633650
let (inner, stack, script_code) =
634-
from_txdata(&spk, &script_sig, &[]).expect("parse txdata");
651+
from_txdata(&spk, &script_sig, &empty_wit).expect("parse txdata");
635652
assert_eq!(inner, Inner::Script(miniscript, ScriptType::Sh));
636653
assert_eq!(stack, Stack::from(vec![]));
637654
assert_eq!(script_code, redeem_script);
638655

639656
// nonempty witness
640-
let err = from_txdata(&spk, &script_sig, &[vec![]]).unwrap_err();
657+
let wit = Witness::from_vec(vec![vec![]]);
658+
let err = from_txdata(&spk, &script_sig, &wit).unwrap_err();
641659
assert_eq!(&err.to_string(), "legacy spend had nonempty witness");
642660
}
643661

@@ -650,17 +668,18 @@ mod tests {
650668

651669
let witness_script = miniscript.encode();
652670
let wit_hash = sha256::Hash::hash(&witness_script[..]).into();
653-
let wit_stack = vec![witness_script.to_bytes()];
671+
let wit_stack = Witness::from_vec(vec![witness_script.to_bytes()]);
654672

655673
let spk = Script::new_v0_wsh(&wit_hash);
656674
let blank_script = bitcoin::Script::new();
657675

658676
// wsh without witness
659-
let err = from_txdata(&spk, &blank_script, &[]).unwrap_err();
677+
let err = from_txdata(&spk, &blank_script, &Witness::default()).unwrap_err();
660678
assert_eq!(&err.to_string(), "unexpected end of stack");
661679

662680
// with incorrect witness
663-
let err = from_txdata(&spk, &blank_script, &[spk.to_bytes()]).unwrap_err();
681+
let wit = Witness::from_vec(vec![spk.to_bytes()]);
682+
let err = from_txdata(&spk, &blank_script, &wit).unwrap_err();
664683
assert_eq!(&err.to_string()[0..12], "parse error:");
665684

666685
// with correct witness
@@ -687,7 +706,7 @@ mod tests {
687706

688707
let witness_script = miniscript.encode();
689708
let wit_hash = sha256::Hash::hash(&witness_script[..]).into();
690-
let wit_stack = vec![witness_script.to_bytes()];
709+
let wit_stack = Witness::from_vec(vec![witness_script.to_bytes()]);
691710

692711
let redeem_script = Script::new_v0_wsh(&wit_hash);
693712
let script_sig = script::Builder::new()
@@ -699,15 +718,16 @@ mod tests {
699718
let spk = Script::new_p2sh(&rs_hash);
700719

701720
// shwsh without witness or scriptsig
702-
let err = from_txdata(&spk, &blank_script, &[]).unwrap_err();
721+
let err = from_txdata(&spk, &blank_script, &Witness::default()).unwrap_err();
703722
assert_eq!(&err.to_string(), "unexpected end of stack");
704-
let err = from_txdata(&spk, &script_sig, &[]).unwrap_err();
723+
let err = from_txdata(&spk, &script_sig, &Witness::default()).unwrap_err();
705724
assert_eq!(&err.to_string(), "unexpected end of stack");
706725
let err = from_txdata(&spk, &blank_script, &wit_stack).unwrap_err();
707726
assert_eq!(&err.to_string(), "unexpected end of stack");
708727

709728
// with incorrect witness
710-
let err = from_txdata(&spk, &script_sig, &[spk.to_bytes()]).unwrap_err();
729+
let wit = Witness::from_vec(vec![spk.to_bytes()]);
730+
let err = from_txdata(&spk, &script_sig, &wit).unwrap_err();
711731
assert_eq!(&err.to_string()[0..12], "parse error:");
712732

713733
// with incorrect scriptsig

src/interpreter/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
//! assuming that the spent coin was descriptor controlled.
2020
//!
2121
22+
use bitcoin::blockdata::witness::Witness;
2223
use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d};
2324
use bitcoin::util::sighash;
2425
use bitcoin::{self, secp256k1};
@@ -54,7 +55,7 @@ impl<'txin> Interpreter<'txin> {
5455
pub fn from_txdata(
5556
spk: &bitcoin::Script,
5657
script_sig: &'txin bitcoin::Script,
57-
witness: &'txin [Vec<u8>],
58+
witness: &'txin Witness,
5859
age: u32,
5960
height: u32,
6061
) -> Result<Self, Error> {

0 commit comments

Comments
 (0)