@@ -17,7 +17,7 @@ use expression::{self, FromTree};
1717use miniscript:: { limits:: TAPROOT_MAX_NODE_COUNT , Miniscript } ;
1818use std:: cmp:: { self , max} ;
1919use std:: hash;
20- use std:: sync:: { Arc , RwLock } ;
20+ use std:: sync:: { Arc , Mutex } ;
2121use std:: { fmt, str:: FromStr } ;
2222use Tap ;
2323use { Error , MiniscriptKey } ;
@@ -46,19 +46,21 @@ pub struct Tr<Pk: MiniscriptKey> {
4646 /// This will be [`None`] when the descriptor is not derived.
4747 /// This information will be cached automatically when it is required
4848 //
49- // It is also possible to wrap this in a further Arc<RwLock...> so that the cache
50- // is shared across clones of the this descriptor. But this (slightly) complicates
51- // the code, and it might be desirable for clone to keep separate caches
52- spend_info : RwLock < Option < Arc < TaprootSpendInfo > > > ,
49+ // The inner `Arc` here is because Rust does not allow us to return a reference
50+ // to the contents of the `Option` from inside a `MutexGuard`. There is no outer
51+ // `Arc` because when this structure is cloned, we create a whole new mutex.
52+ spend_info : Mutex < Option < Arc < TaprootSpendInfo > > > ,
5353}
5454
5555impl < Pk : MiniscriptKey > Clone for Tr < Pk > {
5656 fn clone ( & self ) -> Self {
57+ // When cloning, construct a new Mutex so that distinct clones don't
58+ // cause blocking between each other. We clone only the internal `Arc`,
59+ // so the clone is always cheap (in both time and space)
5760 Self {
5861 internal_key : self . internal_key . clone ( ) ,
5962 tree : self . tree . clone ( ) ,
60- // Cloning creates a new instance of RwLock
61- spend_info : RwLock :: new ( None ) ,
63+ spend_info : Mutex :: new ( self . spend_info . lock ( ) . expect ( "Lock poisoned" ) . clone ( ) ) ,
6264 }
6365 }
6466}
@@ -169,7 +171,7 @@ impl<Pk: MiniscriptKey> Tr<Pk> {
169171 Ok ( Self {
170172 internal_key,
171173 tree,
172- spend_info : RwLock :: new ( None ) ,
174+ spend_info : Mutex :: new ( None ) ,
173175 } )
174176 } else {
175177 Err ( Error :: MaxRecursiveDepthExceeded )
@@ -212,64 +214,54 @@ impl<Pk: MiniscriptKey> Tr<Pk> {
212214 {
213215 // If the value is already cache, read it
214216 // read only panics if the lock is poisoned (meaning other thread having a lock panicked)
215- let spend_info = self
216- . spend_info
217- . read ( )
218- . expect ( "Lock poisoned" )
219- . as_ref ( )
220- . map ( Arc :: clone) ;
221-
222- match spend_info {
223- Some ( spend_info) => spend_info,
224- None => {
225- // Get a new secp context
226- // This would be cheap operation after static context support from upstream
227- let secp = secp256k1:: Secp256k1 :: verification_only ( ) ;
228- // Key spend path with no merkle root
229- let data = if self . tree . is_none ( ) {
230- TaprootSpendInfo :: new_key_spend (
231- & secp,
232- self . internal_key . to_x_only_pubkey ( ) ,
233- None ,
234- )
235- } else {
236- let mut builder = TaprootBuilder :: new ( ) ;
237- for ( depth, ms) in self . iter_scripts ( ) {
238- let script = ms. encode ( ) ;
239- builder = builder
240- . add_leaf ( depth, script)
241- . expect ( "Computing spend data on a valid Tree should always succeed" ) ;
217+ let read_lock = self . spend_info . lock ( ) . expect ( "Lock poisoned" ) ;
218+ if let Some ( ref spend_info) = * read_lock {
219+ return spend_info. clone ( ) ;
220+ }
221+ drop ( read_lock) ;
222+
223+ // Get a new secp context
224+ // This would be cheap operation after static context support from upstream
225+ let secp = secp256k1:: Secp256k1 :: verification_only ( ) ;
226+ // Key spend path with no merkle root
227+ let data = if self . tree . is_none ( ) {
228+ TaprootSpendInfo :: new_key_spend ( & secp, self . internal_key . to_x_only_pubkey ( ) , None )
229+ } else {
230+ let mut builder = TaprootBuilder :: new ( ) ;
231+ for ( depth, ms) in self . iter_scripts ( ) {
232+ let script = ms. encode ( ) ;
233+ builder = builder
234+ . add_leaf ( depth, script)
235+ . expect ( "Computing spend data on a valid Tree should always succeed" ) ;
236+ }
237+ // Assert builder cannot error here because we have a well formed descriptor
238+ match builder. finalize ( & secp, self . internal_key . to_x_only_pubkey ( ) ) {
239+ Ok ( data) => data,
240+ Err ( e) => match e {
241+ TaprootBuilderError :: InvalidMerkleTreeDepth ( _) => {
242+ unreachable ! ( "Depth checked in struct construction" )
243+ }
244+ TaprootBuilderError :: NodeNotInDfsOrder => {
245+ unreachable ! ( "Insertion is called in DFS order" )
246+ }
247+ TaprootBuilderError :: OverCompleteTree => {
248+ unreachable ! ( "Taptree is a well formed tree" )
242249 }
243- // Assert builder cannot error here because we have a well formed descriptor
244- match builder. finalize ( & secp, self . internal_key . to_x_only_pubkey ( ) ) {
245- Ok ( data) => data,
246- Err ( e) => match e {
247- TaprootBuilderError :: InvalidMerkleTreeDepth ( _) => {
248- unreachable ! ( "Depth checked in struct construction" )
249- }
250- TaprootBuilderError :: NodeNotInDfsOrder => {
251- unreachable ! ( "Insertion is called in DFS order" )
252- }
253- TaprootBuilderError :: OverCompleteTree => {
254- unreachable ! ( "Taptree is a well formed tree" )
255- }
256- TaprootBuilderError :: InvalidInternalKey ( _) => {
257- unreachable ! ( "Internal key checked for validity" )
258- }
259- TaprootBuilderError :: IncompleteTree => {
260- unreachable ! ( "Taptree is a well formed tree" )
261- }
262- TaprootBuilderError :: EmptyTree => {
263- unreachable ! ( "Taptree is a well formed tree with atleast 1 element" )
264- }
265- } ,
250+ TaprootBuilderError :: InvalidInternalKey ( _) => {
251+ unreachable ! ( "Internal key checked for validity" )
266252 }
267- } ;
268- let spend_info = Arc :: new ( data) ;
269- * self . spend_info . write ( ) . expect ( "Lock poisoned" ) = Some ( Arc :: clone ( & spend_info) ) ;
270- spend_info
253+ TaprootBuilderError :: IncompleteTree => {
254+ unreachable ! ( "Taptree is a well formed tree" )
255+ }
256+ TaprootBuilderError :: EmptyTree => {
257+ unreachable ! ( "Taptree is a well formed tree with atleast 1 element" )
258+ }
259+ } ,
271260 }
272- }
261+ } ;
262+ let spend_info = Arc :: new ( data) ;
263+ * self . spend_info . lock ( ) . expect ( "Lock poisoned" ) = Some ( spend_info. clone ( ) ) ;
264+ spend_info
273265 }
274266}
275267
@@ -387,7 +379,7 @@ where
387379 Ok ( Tr {
388380 internal_key : expression:: terminal ( key, Pk :: from_str) ?,
389381 tree : None ,
390- spend_info : RwLock :: new ( None ) ,
382+ spend_info : Mutex :: new ( None ) ,
391383 } )
392384 }
393385 2 => {
@@ -403,7 +395,7 @@ where
403395 Ok ( Tr {
404396 internal_key : expression:: terminal ( key, Pk :: from_str) ?,
405397 tree : Some ( ret) ,
406- spend_info : RwLock :: new ( None ) ,
398+ spend_info : Mutex :: new ( None ) ,
407399 } )
408400 }
409401 _ => {
@@ -668,7 +660,7 @@ impl<P: MiniscriptKey, Q: MiniscriptKey> TranslatePk<P, Q> for Tr<P> {
668660 Some ( tree) => Some ( tree. translate_helper ( & mut translatefpk, & mut translatefpkh) ?) ,
669661 None => None ,
670662 } ,
671- spend_info : RwLock :: new ( None ) ,
663+ spend_info : Mutex :: new ( None ) ,
672664 } ;
673665 Ok ( translate_desc)
674666 }
0 commit comments