2
2
3
3
use core:: { cmp, fmt, hash} ;
4
4
5
- #[ cfg( not( test) ) ] // https://github.com/rust-lang/rust/issues/121684
6
- use bitcoin:: secp256k1;
7
- use bitcoin:: taproot:: {
8
- LeafVersion , TaprootBuilder , TaprootSpendInfo , TAPROOT_CONTROL_BASE_SIZE ,
9
- TAPROOT_CONTROL_NODE_SIZE ,
10
- } ;
5
+ use bitcoin:: taproot:: { TAPROOT_CONTROL_BASE_SIZE , TAPROOT_CONTROL_NODE_SIZE } ;
11
6
use bitcoin:: { opcodes, Address , Network , ScriptBuf , Weight } ;
12
7
use sync:: Arc ;
13
8
@@ -45,7 +40,7 @@ pub struct Tr<Pk: MiniscriptKey> {
45
40
// The inner `Arc` here is because Rust does not allow us to return a reference
46
41
// to the contents of the `Option` from inside a `MutexGuard`. There is no outer
47
42
// `Arc` because when this structure is cloned, we create a whole new mutex.
48
- spend_info : Mutex < Option < Arc < TaprootSpendInfo > > > ,
43
+ spend_info : Mutex < Option < Arc < TrSpendInfo < Pk > > > > ,
49
44
}
50
45
51
46
impl < Pk : MiniscriptKey > Clone for Tr < Pk > {
@@ -120,46 +115,21 @@ impl<Pk: MiniscriptKey> Tr<Pk> {
120
115
}
121
116
}
122
117
123
- /// Compute the [`TaprootSpendInfo`] associated with this descriptor if spend data is `None` .
118
+ /// Obtain the spending information for this [`Tr`] .
124
119
///
125
- /// If spend data is already computed (i.e it is not `None`), this does not recompute it.
120
+ /// The first time this method is called, it computes the full Taproot Merkle tree of
121
+ /// all branches as well as the output key which appears on-chain. This is fairly
122
+ /// expensive since it requires hashing every branch and then doing an elliptic curve
123
+ /// operation. The result is cached and reused on subsequent calls.
126
124
///
127
- /// [`TaprootSpendInfo`] is only required for spending via the script paths.
128
- pub fn spend_info ( & self ) -> Arc < TaprootSpendInfo >
125
+ /// This data is needed to compute the Taproot output, so this method is implicitly
126
+ /// called through [`Self::script_pubkey`], [`Self::address`], etc. It is also needed
127
+ /// to compute the hash needed to sign the output.
128
+ pub fn spend_info ( & self ) -> TrSpendInfo < Pk >
129
129
where
130
130
Pk : ToPublicKey ,
131
131
{
132
- // If the value is already cache, read it
133
- // read only panics if the lock is poisoned (meaning other thread having a lock panicked)
134
- let read_lock = self . spend_info . lock ( ) . expect ( "Lock poisoned" ) ;
135
- if let Some ( ref spend_info) = * read_lock {
136
- return Arc :: clone ( spend_info) ;
137
- }
138
- drop ( read_lock) ;
139
-
140
- // Get a new secp context
141
- // This would be cheap operation after static context support from upstream
142
- let secp = secp256k1:: Secp256k1 :: verification_only ( ) ;
143
- // Key spend path with no merkle root
144
- let data = if self . tree . is_none ( ) {
145
- TaprootSpendInfo :: new_key_spend ( & secp, self . internal_key . to_x_only_pubkey ( ) , None )
146
- } else {
147
- let mut builder = TaprootBuilder :: new ( ) ;
148
- for leaf in self . leaves ( ) {
149
- let script = leaf. miniscript ( ) . encode ( ) ;
150
- builder = builder
151
- . add_leaf ( leaf. depth ( ) , script)
152
- . expect ( "Computing spend data on a valid Tree should always succeed" ) ;
153
- }
154
- // Assert builder cannot error here because we have a well formed descriptor
155
- match builder. finalize ( & secp, self . internal_key . to_x_only_pubkey ( ) ) {
156
- Ok ( data) => data,
157
- Err ( _) => unreachable ! ( "We know the builder can be finalized" ) ,
158
- }
159
- } ;
160
- let spend_info = Arc :: new ( data) ;
161
- * self . spend_info . lock ( ) . expect ( "Lock poisoned" ) = Some ( Arc :: clone ( & spend_info) ) ;
162
- spend_info
132
+ TrSpendInfo :: from_tr ( self )
163
133
}
164
134
165
135
/// Checks whether the descriptor is safe.
@@ -508,7 +478,7 @@ where
508
478
absolute_timelock : None ,
509
479
} ;
510
480
let mut min_wit_len = None ;
511
- for leaf in desc . leaves ( ) {
481
+ for leaf in spend_info . leaves ( ) {
512
482
let mut satisfaction = if allow_mall {
513
483
match leaf. miniscript ( ) . build_template ( provider) {
514
484
s @ Satisfaction { stack : Witness :: Stack ( _) , .. } => s,
@@ -525,12 +495,10 @@ where
525
495
_ => unreachable ! ( ) ,
526
496
} ;
527
497
528
- let leaf_script = ( leaf. compute_script ( ) , LeafVersion :: TapScript ) ;
529
- let control_block = spend_info
530
- . control_block ( & leaf_script)
531
- . expect ( "Control block must exist in script map for every known leaf" ) ;
498
+ let script = ScriptBuf :: from ( leaf. script ( ) ) ;
499
+ let control_block = leaf. control_block ( ) . clone ( ) ;
532
500
533
- wit. push ( Placeholder :: TapScript ( leaf_script . 0 ) ) ;
501
+ wit. push ( Placeholder :: TapScript ( script ) ) ;
534
502
wit. push ( Placeholder :: TapControlBlock ( control_block) ) ;
535
503
536
504
let wit_size = witness_size ( wit) ;
0 commit comments