22
33use core:: { cmp, fmt, hash} ;
44
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 } ;
116use bitcoin:: { opcodes, Address , Network , ScriptBuf , Weight } ;
127use sync:: Arc ;
138
@@ -45,7 +40,7 @@ pub struct Tr<Pk: MiniscriptKey> {
4540 // The inner `Arc` here is because Rust does not allow us to return a reference
4641 // to the contents of the `Option` from inside a `MutexGuard`. There is no outer
4742 // `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 > > > > ,
4944}
5045
5146impl < Pk : MiniscriptKey > Clone for Tr < Pk > {
@@ -120,46 +115,21 @@ impl<Pk: MiniscriptKey> Tr<Pk> {
120115 }
121116 }
122117
123- /// Compute the [`TaprootSpendInfo`] associated with this descriptor if spend data is `None` .
118+ /// Obtain the spending information for this [`Tr`] .
124119 ///
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.
126124 ///
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 >
129129 where
130130 Pk : ToPublicKey ,
131131 {
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 )
163133 }
164134
165135 /// Checks whether the descriptor is safe.
@@ -508,7 +478,7 @@ where
508478 absolute_timelock : None ,
509479 } ;
510480 let mut min_wit_len = None ;
511- for leaf in desc . leaves ( ) {
481+ for leaf in spend_info . leaves ( ) {
512482 let mut satisfaction = if allow_mall {
513483 match leaf. miniscript ( ) . build_template ( provider) {
514484 s @ Satisfaction { stack : Witness :: Stack ( _) , .. } => s,
@@ -525,12 +495,10 @@ where
525495 _ => unreachable ! ( ) ,
526496 } ;
527497
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 ( ) ;
532500
533- wit. push ( Placeholder :: TapScript ( leaf_script . 0 ) ) ;
501+ wit. push ( Placeholder :: TapScript ( script ) ) ;
534502 wit. push ( Placeholder :: TapControlBlock ( control_block) ) ;
535503
536504 let wit_size = witness_size ( wit) ;
0 commit comments