19
19
//! `https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki`
20
20
//!
21
21
22
+ use bitcoin:: schnorr:: XOnlyPublicKey ;
23
+ use util:: { script_is_v1_tr, witness_size} ;
24
+
22
25
use super :: { sanity_check, Psbt } ;
23
26
use super :: { Error , InputError , PsbtInputSatisfier } ;
24
27
use bitcoin:: blockdata:: witness:: Witness ;
25
28
use bitcoin:: secp256k1:: { self , Secp256k1 } ;
29
+ use bitcoin:: util:: taproot:: LeafVersion ;
26
30
use bitcoin:: { self , PublicKey , Script } ;
27
31
use descriptor:: DescriptorTrait ;
28
32
use interpreter;
29
33
use Descriptor ;
30
34
use Miniscript ;
31
- use { BareCtx , Legacy , Segwitv0 } ;
35
+ use Satisfier ;
36
+ use { BareCtx , Legacy , Segwitv0 , Tap } ;
37
+
38
+ // Satisfy the taproot descriptor. It is not possible to infer the complete
39
+ // descriptor from psbt because the information about all the scripts might not
40
+ // be present. Also, currently the spec does not support hidden branches, so
41
+ // inferring a descriptor is not possible
42
+ fn construct_tap_witness (
43
+ spk : & Script ,
44
+ sat : & PsbtInputSatisfier ,
45
+ allow_mall : bool ,
46
+ ) -> Result < Vec < Vec < u8 > > , InputError > {
47
+ assert ! ( script_is_v1_tr( & spk) ) ;
48
+
49
+ // try the script spend path first
50
+ if let Some ( sig) =
51
+ <PsbtInputSatisfier as Satisfier < XOnlyPublicKey > >:: lookup_tap_key_spend_sig ( sat)
52
+ {
53
+ return Ok ( vec ! [ sig. to_vec( ) ] ) ;
54
+ }
55
+ // Next script spends
56
+ let ( mut min_wit, mut min_wit_len) = ( None , None ) ;
57
+ if let Some ( block_map) =
58
+ <PsbtInputSatisfier as Satisfier < XOnlyPublicKey > >:: lookup_tap_control_block_map ( sat)
59
+ {
60
+ for ( control_block, ( script, ver) ) in block_map {
61
+ if * ver != LeafVersion :: TapScript {
62
+ // We don't know how to satisfy non default version scripts yet
63
+ continue ;
64
+ }
65
+ let ms = match Miniscript :: < XOnlyPublicKey , Tap > :: parse_insane ( script) {
66
+ Ok ( ms) => ms,
67
+ Err ( ..) => continue , // try another script
68
+ } ;
69
+ let mut wit = if allow_mall {
70
+ match ms. satisfy_malleable ( sat) {
71
+ Ok ( ms) => ms,
72
+ Err ( ..) => continue ,
73
+ }
74
+ } else {
75
+ match ms. satisfy ( sat) {
76
+ Ok ( ms) => ms,
77
+ Err ( ..) => continue ,
78
+ }
79
+ } ;
80
+ wit. push ( ms. encode ( ) . into_bytes ( ) ) ;
81
+ wit. push ( control_block. serialize ( ) ) ;
82
+ let wit_len = Some ( witness_size ( & wit) ) ;
83
+ if min_wit_len. is_some ( ) && wit_len > min_wit_len {
84
+ continue ;
85
+ } else {
86
+ // store the minimum
87
+ min_wit = Some ( wit) ;
88
+ min_wit_len = wit_len;
89
+ }
90
+ }
91
+ min_wit. ok_or ( InputError :: CouldNotSatisfyTr )
92
+ } else {
93
+ // No control blocks found
94
+ Err ( InputError :: CouldNotSatisfyTr )
95
+ }
96
+ }
97
+
32
98
// Get the scriptpubkey for the psbt input
33
99
fn get_scriptpubkey ( psbt : & Psbt , index : usize ) -> Result < & Script , InputError > {
34
100
let script_pubkey;
@@ -299,16 +365,28 @@ pub fn finalize_helper<C: secp256k1::Verification>(
299
365
300
366
// Actually construct the witnesses
301
367
for index in 0 ..psbt. inputs . len ( ) {
302
- // Get a descriptor for this input
303
- let desc = get_descriptor ( & psbt, index) . map_err ( |e| Error :: InputError ( e, index) ) ?;
368
+ let ( witness, script_sig) = {
369
+ let spk = get_scriptpubkey ( psbt, index) . map_err ( |e| Error :: InputError ( e, index) ) ?;
370
+ let sat = PsbtInputSatisfier :: new ( & psbt, index) ;
304
371
305
- //generate the satisfaction witness and scriptsig
306
- let ( witness, script_sig) = if !allow_mall {
307
- desc. get_satisfaction ( PsbtInputSatisfier :: new ( & psbt, index) )
308
- } else {
309
- desc. get_satisfaction_mall ( PsbtInputSatisfier :: new ( & psbt, index) )
310
- }
311
- . map_err ( |e| Error :: InputError ( InputError :: MiniscriptError ( e) , index) ) ?;
372
+ if script_is_v1_tr ( spk) {
373
+ // Deal with tr case separately, unfortunately we cannot infer the full descriptor for Tr
374
+ let wit = construct_tap_witness ( spk, & sat, allow_mall)
375
+ . map_err ( |e| Error :: InputError ( e, index) ) ?;
376
+ ( wit, Script :: new ( ) )
377
+ } else {
378
+ // Get a descriptor for this input.
379
+ let desc = get_descriptor ( & psbt, index) . map_err ( |e| Error :: InputError ( e, index) ) ?;
380
+
381
+ //generate the satisfaction witness and scriptsig
382
+ if !allow_mall {
383
+ desc. get_satisfaction ( PsbtInputSatisfier :: new ( & psbt, index) )
384
+ } else {
385
+ desc. get_satisfaction_mall ( PsbtInputSatisfier :: new ( & psbt, index) )
386
+ }
387
+ . map_err ( |e| Error :: InputError ( InputError :: MiniscriptError ( e) , index) ) ?
388
+ }
389
+ } ;
312
390
313
391
let input = & mut psbt. inputs [ index] ;
314
392
//Fill in the satisfactions
@@ -323,12 +401,24 @@ pub fn finalize_helper<C: secp256k1::Verification>(
323
401
Some ( witness)
324
402
} ;
325
403
//reset everything
326
- input. redeem_script = None ;
327
- input. partial_sigs . clear ( ) ;
328
- input. sighash_type = None ;
329
- input. redeem_script = None ;
330
- input. bip32_derivation . clear ( ) ;
331
- input. witness_script = None ;
404
+ input. partial_sigs . clear ( ) ; // 0x02
405
+ input. sighash_type = None ; // 0x03
406
+ input. redeem_script = None ; // 0x04
407
+ input. witness_script = None ; // 0x05
408
+ input. bip32_derivation . clear ( ) ; // 0x05
409
+ // finalized witness 0x06 and 0x07 are not clear
410
+ // 0x09 Proof of reserves not yet supported
411
+ input. ripemd160_preimages . clear ( ) ; // 0x0a
412
+ input. sha256_preimages . clear ( ) ; // 0x0b
413
+ input. hash160_preimages . clear ( ) ; // 0x0c
414
+ input. hash256_preimages . clear ( ) ; // 0x0d
415
+ // psbt v2 fields till 0x012 not supported
416
+ input. tap_key_sig = None ; // 0x013
417
+ input. tap_script_sigs . clear ( ) ; // 0x014
418
+ input. tap_scripts . clear ( ) ; // 0x015
419
+ input. tap_key_origins . clear ( ) ; // 0x16
420
+ input. tap_internal_key = None ; // x017
421
+ input. tap_merkle_root = None ; // 0x018
332
422
}
333
423
// Double check everything with the interpreter
334
424
// This only checks whether the script will be executed
0 commit comments